Java 在SQLServerJDBC中使用表值参数
有谁能提供一些关于如何在SQLServerJDBC中使用表值参数TVP的指导吗?我使用的是Microsoft提供的SQL Server驱动程序的6.0版本,我已经回顾了 这两个示例都显示了从Connection.prepareStatement调用获取SQLServerPreparedStatement casted对象,以便调用setStructured方法。这难道不会阻止使用标准连接池(如DBCP2)吗 我注意到另一条堆栈溢出注释中的一条注释,该注释表示可以使用stmt.setObject方法: 作为强制转换PreparedStatement的替代方法,您可以将SQLServerDataTable实例传递给PreparedStatement.setObjectint对象方法。这适用于dbo模式中定义的TVP类型阿伦鲁7月15日19:18 虽然我在尝试此操作时出错,并且类型在dbo模式中Java 在SQLServerJDBC中使用表值参数,java,sql-server,jdbc,table-valued-parameters,Java,Sql Server,Jdbc,Table Valued Parameters,有谁能提供一些关于如何在SQLServerJDBC中使用表值参数TVP的指导吗?我使用的是Microsoft提供的SQL Server驱动程序的6.0版本,我已经回顾了 这两个示例都显示了从Connection.prepareStatement调用获取SQLServerPreparedStatement casted对象,以便调用setStructured方法。这难道不会阻止使用标准连接池(如DBCP2)吗 我注意到另一条堆栈溢出注释中的一条注释,该注释表示可以使用stmt.setObject方
Exception in thread "main" com.microsoft.sqlserver.jdbc.SQLServerException: The Table-Valued Parameter must have a valid type name.
这是我的密码:
// JAVA
private static void tableParameters(DataSource ds) throws SQLException {
final String sql = "EXEC dbo.GetAccountsFromTable @accountIds=?";
final List<Integer> accountIds = generateIntegers(50, 1_000_000);
try (Connection conn = ds.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql))
{
SQLServerDataTable accounts = new SQLServerDataTable();
accounts.addColumnMetadata("item", java.sql.Types.INTEGER);
for (Integer aid : accountIds)
accounts.addRow(aid.toString());
stmt.setObject(1, accounts);
try (ResultSet rs = stmt.executeQuery())
{
while (rs.next()) {
System.out.println(rs.getInt(1));
}
}
}
}
-- TSQL
create type dbo.IntegerTable AS TABLE (item INT);
CREATE PROCEDURE dbo.GetAccountsFromTable(@accountIds dbo.IntegerTable READONLY)
AS
BEGIN
IF OBJECT_ID('tempdb..#AccountIds') IS NOT NULL
DROP TABLE #AccountIds
CREATE TABLE #AccountIds (id INTEGER)
INSERT INTO #AccountIds
SELECT * FROM @accountIds
SELECT * FROM #AccountIds
END
任何帮助或指导都将不胜感激。谢谢 re:使用PreparedStatementsetObject
我把它玩弄了一下,也没法让它工作。也许是6.0预览版中的一个功能从最终版本中删除了
re:使用SQLServerPreparedStatement对象
我不明白为什么这会阻止使用DBCP2或任何其他连接池本身,尽管这可能会影响DBCP2的poolPreparedStatements选项,默认情况下该选项为false。尽管如此,如果一个人想要创建一个合适的PreparedStatement对象,并且仍然需要使用setStructured,那么当我刚才尝试它时,它工作得很好:
字符串sql=EXEC dbo.GetAccountsFromTable?;
尝试
连接连接=DriverManager.getConnectionconnectionUrl;
PreparedStatement stmt=conn.prepareStatementsql{
SQLServerDataTable帐户=新SQLServerDataTable;
accounts.addColumnMetadataitem,java.sql.Types.INTEGER;
accounts.addRow123;
accounts.addRow234;
SQLServerPreparedStatement stmt.setStructured1,dbo.IntegerTable,accounts;
try ResultSet rs=stmt.executeQuery{
而rs.next{
System.out.printlnrs.getInt1;
}
}
}捕获异常e{
e、 printStackTraceSystem.err;
}
但是,鉴于我们正在调用一个存储过程,在setStructured调用中使用CallableStatement对象和对SQLServerCallableStatement的快速转换,而不是PreparedStatement对象,这可能是一种很好的形式。DBCP2有一个DelegatingStatement.getInnermostDelegate方法来获取由Microsoft驱动程序创建的PreparedStatement对象。我不太喜欢跳转所需要的技巧——即使添加了错误检查,代码看起来也很脆弱。TVP是一个特定于SqlServer的东西,因此使用所需的假设和强制转换可能并不坏
private static int testTvp(DataSource ds, List<Integer> accountIds) throws SQLException {
final String sql = "EXEC dgTest.GetAccountsFromTvp @accountIds=?";
try (Connection conn = ds.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
DelegatingPreparedStatement dstmt = (DelegatingPreparedStatement)stmt;
SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)dstmt.getInnermostDelegate();
SQLServerDataTable accounts = new SQLServerDataTable();
accounts.addColumnMetadata("token", java.sql.Types.INTEGER);
for (Integer aid : accountIds)
accounts.addRow(aid);
pstmt.setStructured(1, "dgTest.IntegerTable", accounts);
//// NOTE: The below works for JTDS driver, official MS driver said no result sets were returned
//try (ResultSet rs = pstmt.executeQuery()) {
// return sumInts(rs);
//}
if (pstmt.execute()) {
try (ResultSet rs = pstmt.getResultSet()) {
return sumInts(rs);
}
}
return -1;
}
}