2016-11-02 5 views
1

SQL Server JDBCでテーブル値パラメータ(TVP)を使用する方法については、私は、Microsoftが提供するSQL Serverドライバのバージョン6.0を使用しています、と私はofficial documentationだけでなく、より多くの有用な例を検討しているSQL Server JDBCでテーブル値パラメータを使用する

How to pass Table-Valued parameters from java to sql server stored procedure?

示しConnection.prepareStatementからSQLServerPreparedStatementキャストオブジェクトを取得の両方の例電話をかけてsetStructuredメソッドに電話をかけてください。これにより、DBCP2などの標準接続プールの使用が妨げられないでしょうか?

私は代わりにstmt.setObjectメソッドを使用することができるかもしれないと言って、他のスタックオーバーフローのコメントからのコメントに気づい:PreparedStatementをキャストする代わりに

を、あなたはPreparedStatementのにSQLServerDataTableインスタンスを渡すことができます。 setObject(int、Object)メソッドです。これは、dboスキーマで定義されたTVPタイプに対して機能しました。 - 19時18分

でallenru 7月15日私はこれをしようとしたとき、私はエラーを得て、タイプはdboスキーマでですが...

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 

ご迷惑をおかけして申し訳ございません。ありがとう!

答えて

1

ここで私が使用したルートがあります。 DBCP2には、Microsoftドライバによって作成されたPreparedStatementオブジェクトを取得するメソッドDelegatingStatement.getInnermostDelegateがあります。私はジャンプする必要があるフープの巨大なファンではない - たとえエラーチェックが追加されたとしても、コードは脆いようだ。 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; 
    } 
} 
0

再:PreparedStatement#setObject

を使用して、私はそれで少し周りにだまされ、私はそれがいずれかの仕事を得ることができませんでした。おそらく、それは6.0リリースのフィーチャーで、最終リリースから取り上げられたものです。

再:それはDBCP2(またはその他の接続プール)を使用して妨げるなぜそれがDBCP2のpoolPreparedStatementsオプションに影響を(これはfalseあるかもしれないが、私は、自体が表示されていないSQLServerPreparedStatementオブジェクト

を使用してデフォルトで)。 1はsetStructuredを使用するために必要な、まだ「適切な」PreparedStatementオブジェクトとを作成したい場合、私はちょうど今それをしようとしたとき、まだ、これがうまく働いた:

String sql = "EXEC dbo.GetAccountsFromTable ?"; 
try (
     Connection conn = DriverManager.getConnection(connectionUrl); 
     PreparedStatement stmt = conn.prepareStatement(sql)) { 
    SQLServerDataTable accounts = new SQLServerDataTable(); 
    accounts.addColumnMetadata("item", java.sql.Types.INTEGER); 
    accounts.addRow(123); 
    accounts.addRow(234); 
    ((SQLServerPreparedStatement) stmt).setStructured(1, "dbo.IntegerTable", accounts); 
    try (ResultSet rs = stmt.executeQuery()) { 
     while (rs.next()) { 
      System.out.println(rs.getInt(1)); 
     } 
    } 
} catch (Exception e) { 
    e.printStackTrace(System.err); 
} 

をしかし、我々はそれがあるかもしれないストアドプロシージャを呼び出していることを考えるとオブジェクトの代わりにCallableStatementオブジェクト(setStructuredコールの場合はSQLServerCallableStatementへの簡易キャスト)を使用するための「良いフォーム」。

関連する問題