1

我正在实现一种模式来解决 JDBC 限制。对于准备好的语句,JDBC 将占位符的数量限制为 2100。为了解决这个问题,我使用了一个包含 2100 多个值的 xml 字符串,并使用函数 tf_splitxml 在 SQL Server 端解析它。我正在为使用准备好的语句的〜4个Java方法执行此操作。

此 tf_splitxml 仅构造包含所有值的单个列“令牌”。所以一个xml字符串:

'<node><value>1</value><value>2</value></node>' 

将转换为包含两行的列,值为 1 和 2。

这种模式似乎适用于 select 语句,但它不适用于 update 语句。这是一般模式:

declare @xml xml; set @xml = ?; --Replaced with xml string in PreparedStatement

update tableX
...
where ids in (select token from tf_splitxml(@xml));

它告诉我将 nvarchar 值转换为数据类型 int 时转换失败。[对于上述 xml 字符串]。奇怪的是,如果我提取prepared statement设置的查询,我可以在SQL Server中完美运行!

我的想法:

  1. 在这 4 种方法中,有 3 种使用这种 xml 模式;这 3 个都是 select 语句并使用 executeQuery()。第 4 个失败的方法是更新语句并使用 executeUpdate()。也许问题与准备好的语句预编译sql的方式有关?

我尝试过的事情:

  1. 我创建了一个可以保存从 tf_splitxml 生成的令牌的表。对于失败的方法,在 JDBC 抛出错误之前永远不会调用 tf_splitxml。

  2. 在 Java 方面,我使用的是 ps.setString(index, convertToXML(idsArray))。这适用于前 3 种方法,即使我的 @xml 不是字符串(它被声明为 xml 变量)。我尝试将其切换到 SQLXML 对象,但无济于事。我仍然可以正常使用相同的 3/4 方法。

  3. 我可以直接在我的 SQL Server 编辑器中运行所有准备好的查询,效果很好。

提前致以最诚挚的谢意!:)

4

1 回答 1

1

该代码看起来很疯狂,请查看我的ChunkWorkTemplate。这是一个简单的例子:

public void delete(final List<Integer> employeeIds) {
  new ChunkWorkTemplate<Integer>(50, employeeIds) {
    protected void executeOnChunk(List<Integer> chunk) {
      Session session = getSession();
      Query query = session.createSQLQuery("delete from Employee where employeeId in (:employeeIds)");
      query.setParameterList("employeeIds", chunk);
      query.executeUpdate();
    }
  }.execute();
}

请注意,模板的第一个参数是块大小,您可以将其设置为您喜欢的任何值。基本上,它会将输入集合分块并分块执行主体。因此,在上面的示例中,如果您有 207 个员工 ID,块大小为 50,您将有 5 个块 (50+50+50+50+7)。我写这篇文章是为了解决您面临的确切问题。希望这可以帮助。

于 2013-05-16T00:52:52.380 回答