2016-11-02 6 views
1

누구나 SQL Server JDBC에서 TVP (테이블 값 매개 변수)를 사용하는 방법에 대한 지침을 제공 할 수 있습니까? 나는 마이크로 소프트에서 제공하는 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 유형에 적용됩니다. -이 시도 때 오류를 얻고, 유형 가 DBO 스키마에이지만 19시 18분

에서 allenru 7월 15일 ... 여기

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 객체

를 사용하여 기본적으로).

그러나
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); 
} 

, 주어진 우리가 할 수있는 저장 프로 시저를 호출하는 것을 : 하나는 "적절한"PreparedStatement 객체를 생성하고 싶었 경우 아직도, 아직도 내가 지금 그것을 시도 할 때이 괜찮 았는데 다음 setStructured을 사용하는 데 필요한 "good form"CallableStatement 개체 (setStructured 호출의 경우 SQLServerCallableStatement으로 빠르게 캐스트 됨)를 사용하려면 PreparedStatement 개체 대신.