如何使用jTDS将表值参数传递给存储过程?

时间:2019-01-03 13:37:56

标签: java sql-server stored-procedures jdbc jtds

我需要使用JTDS jdbc驱动程序调用存储过程。

但是此存储过程需要结构类型作为参数。 Jtds CallableStatement没有设置结构的方法,因此我尝试将其强制转换为SQLServerCallableStatement并设置所需的结构。 我使用的代码如下

            Connection con = ds.getConnection();
            CallableStatement call = con.prepareCall("{call getErrosSKF ?,?,?,?}");
            call.setString("agrupador", agrupador);
            call.setDate(2, new Date(dataInicio.getTimeInMillis()));
            call.setDate(3, new Date(dataFim.getTimeInMillis()));   

            SQLServerDataTable areas = new SQLServerDataTable();
            areas.addColumnMetadata("id",Types.INTEGER);
            for(Integer a : skfIdAreas) {
                areas.addRow(a);
            }
             // generate an exception
            ((SQLServerCallableStatement) call).setStructured(4, "erroSKFTable", areas);

但是我无法投放,因为它会生成一个异常,说明 JtdsCallableStatement无法转换为SqlServerCallableStatemen

我可以使用替代方法吗?

1 个答案:

答案 0 :(得分:1)

对表值参数(TVP)的支持是Microsoft的SQL Server JDBC驱动程序的新增功能,事实上,据...

System Requirements for the JDBC Driver

... Microsoft当前没有可用的JDBC驱动程序可与JRE_6一起使用。您可以 尝试从Microsoft找到一个古老的JDBC驱动程序,但是它仍然不能直接支持TVP,因此您最好还是坚持使用jTDS。

现在jTDS也不直接支持TVP,但是您可以通过以下方式完成任务

  1. 创建临时表
  2. 用数据填充临时表,然后
  3. 使用匿名代码块从临时表填充TVP,然后调用存储过程。

示例:

给出一个名为[phonetic] ...的现有参考表。

letter  word
------  -------
A       Alfa
B       Bravo
C       Charlie
...
Y       Yankee
Z       Zulu

...用户定义的表格类型...

CREATE TYPE [dbo].[LetterListTableType] AS TABLE(
    [seq] [int] NOT NULL,
    [letter] [varchar](1) NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [seq] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)

...以及使用该表类型作为参数的存储过程...

CREATE PROCEDURE [dbo].[GetPhonetic] 
    @letters dbo.LetterListTableType READONLY
AS
BEGIN
    SET NOCOUNT ON;
    SELECT l.seq, l.letter, p.word 
        FROM phonetic p INNER JOIN @letters l on p.letter = l.letter
        ORDER BY l.seq;
END

...以下Java代码...

// 0. create some test data
String[] letters = new String[] { "G", "o", "r", "d" };
//
// 1. create temporary table
Statement s = conn.createStatement();
s.executeUpdate("CREATE TABLE #tmp (seq INT IDENTITY PRIMARY KEY, letter VARCHAR(1))");
//
// 2. populate temporary table with letters to look up
PreparedStatement ps = conn.prepareStatement("INSERT INTO #tmp (letter) VALUES (?)");
for (String letter : letters) {
    ps.setString(1, letter);
    ps.addBatch();
}
ps.executeBatch();
//
// 3. use anonymous code block to pass table-valued parameter to stored procedure
String sql = 
          "SET NOCOUNT ON; "
        + "DECLARE @tvp dbo.LetterListTableType; "
        + "INSERT INTO @tvp (seq, letter) SELECT seq, letter FROM #tmp; "
        + "EXEC dbo.GetPhonetic @tvp; ";
ResultSet rs = s.executeQuery(sql);
while (rs.next()) {
    System.out.printf("%s -> %s%n", rs.getString("letter"), rs.getString("word"));
}

...产生

G -> Golf
o -> Oscar
r -> Romeo
d -> Delta