有关占位符的JDBC限制的解决方法因更新语句而失败

时间:2013-05-16 00:36:18

标签: java sql-server jdbc prepared-statement

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

这个tf_splitxml只构造一个包含所有值的列“token”。所以xml字符串为:

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

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

此模式似乎适用于select语句,但更新语句失败。这是一般模式:

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字符串]。奇怪的是,如果我提取由预准备语句设置的查询,我可以在SQL Server中完美地运行它!

我的想法:

  1. 在4种方法中,3种方法使用这种xml模式;这三个都是select语句并使用executeQuery()。第四个失败的方法是更新语句并使用executeUpdate()。也许这个问题与预编译语句预编译sql的方式有关吗?
  2. 我尝试过的事情:

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

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

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

    4. 我最诚挚的感谢! :)

1 个答案:

答案 0 :(得分: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)。我这样写是为了解决你所面临的确切问题。希望这会有所帮助。