在数据量大的时候,向sql server数据库中直接传递表类型的参数往往比用特定分隔符来合并一堆数据显得简洁而快速。下面介绍一下具体的使用方法。当然,也可以参阅microsoft英文官方文档https://msdn.microsoft.com/en-us/library/mt651781
1,首先,需要将sql server的驱动升级到支持表类型的版本,至少要6.0以上,下载地址:https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=11774
2,在数据库中要创建对应的表类型参数。示例(字段名 、字段类型、字段的数量可以任意指定,这里为了方便就构造了两个varchar字段,分别叫columnA、B):
CREATE TYPE MyTableType AS TABLE(ColumnA VARCHAR(36), ColumnB VARCHAR(36));
这样你以MyTableType的格式传到数据库的参数就能直接作为一种TABLE类型来被调用。
3,你可以直接在存储过程中调用这个表类型的参数,示例:
CREATE PROCEDURE [dbo].[procedureName](@TableParam as MyTableType READONLY,)ASBegin...End
4,接下来,就是使用jdbc连接数据库,然后调用存储过程,传递表参数
import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement;import com.microsoft.sqlserver.jdbc.SQLServerDataTable;import java.sql.*;
String url = "jdbc:sqlserver://IP地址:端口;DatabaseName=数据库名;user=用户名;password=密码";Connection con = null;try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); con = DriverManager.getConnection(url); String statement = "call procedureName(?)"; //使用SQLServerCallableStatement对象来构造callablestatement SQLServerCallableStatement cstmt = (SQLServerCallableStatement) con.prepareCall(statement); //使用SQLServerDataTable对象来传递表参数 SQLServerDataTable sourceTable = new SQLServerDataTable(); //在表对象中添加字段的信息 sourceTable.addColumnMetadata("ColumnA", Types.NVARCHAR); sourceTable.addColumnMetadata("ColumnB", Types.NVARCHAR); //添加一行数据用的是addRow方法 sourceTable.addRow("001", "0002"); sourceTable.addRow("005","0006"); //第一个参数是这个表变量在statement中的参数位置,第二个是数据库中表类型的名称,第三个是表对象。 cstmt.setStructured(1, "MyTableType", sourceTable); cstmt.execute();}catch (Exception e){ e.printStackTrace();}finally { if (con!=null){ try { //记得要关闭连接 con.close(); }catch (SQLException e){ e.printStackTrace(); } }}
最后补充几句:
如果是在某些框架(如Hibernate)下连接数据库然后使用表类型的参数,那么通过框架获取的Connection(比如session.getConnection()或session.doWork(con-> ))往往是经过包装的,在这一步:
SQLServerCallableStatement cstmt = (SQLServerCallableStatement) con.prepareCall(statement);
构造SQLServerCallableStatement 时往往会报错,因为这里con.prepareCall生成的statement已经是经过包装的statement了,所以无法转换成其他特定的statement。解决方法有两种:
1是直接按我上面写的,使用jdbc获取数据库连接得到原生的connection,2是使用spring框架自带的NativeJdbcExtractor将包装了的connection转换成原生的,具体的操作可以看http://blog.csdn.net/hehexiaoyou/article/details/21019171