使用 JDBC 参数化 IN 子句的最佳方法是什么?
假设我有一个以下形式的查询
SELECT * FROM MYTABLE WHERE MYCOL in (?)
,并且我想将参数参数化为 in。
是否有一种直接的方法可以在 Java 中使用 JDBC 来执行此操作,并且可以在不修改 SQL 本身的情况下在多个数据库上工作?
我发现的最接近的问题与C#有关,我想知道是否Java/JDBC 有一些不同。
Say that I have a query of the form
SELECT * FROM MYTABLE WHERE MYCOL in (?)
And I want to parameterize the arguments to in.
Is there a straightforward way to do this in Java with JDBC, in a way that could work on multiple databases without modifying the SQL itself?
The closest question I've found had to do with C#, I'm wondering if there is something different for Java/JDBC.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
在 JDBC 中确实没有直接的方法来做到这一点。 一些 JDBC 驱动程序似乎支持
PreparedStatement#setArray()
。我只是不确定是哪些。您可以仅使用
String#join()
和Collections#nCopies()
生成IN
的占位符子句和另一个辅助方法,用于使用PreparedStatement#setObject()
。使用方法如下:
请注意,某些数据库对
IN
子句中允许的值数量有限制。例如,Oracle 对 1000 个项目有此限制。There's indeed no straightforward way to do this in JDBC. Some JDBC drivers seem to support
PreparedStatement#setArray()
on theIN
clause. I am only not sure which ones that are.You could just use a helper method with
String#join()
andCollections#nCopies()
to generate the placeholders forIN
clause and another helper method to set all the values in a loop withPreparedStatement#setObject()
.Here's how you could use it:
Note that some databases have a limit of allowable amount of values in the
IN
clause. Oracle for example has this limit on 1000 items.由于没有人回答大型 IN 子句(超过 100 个)的情况,我将针对这个问题提出我的解决方案,该解决方案非常适合 JDBC。简而言之,我将临时表上的
IN
替换为INNER JOIN
。我所做的就是创建一个批处理 ID 表,根据 RDBMS,我可以将其创建为临时表或内存表。
该表有两列。一列包含来自 IN 子句的 id,另一列包含我动态生成的批次 ID。
在选择之前,将您的 ID 放入具有给定批次 ID 的表中。
然后,您只需将原始查询 IN 子句替换为 ids 表上的 INNER JOIN 匹配项,其中,batch_id 等于当前批次。完成后,批量删除条目。
Since nobody answer the case for a large IN clause (more than 100) I'll throw my solution to this problem which works nicely for JDBC. In short I replace the
IN
with aINNER JOIN
on a tmp table.What I do is make what I call a batch ids table and depending on the RDBMS I may make that a tmp table or in memory table.
The table has two columns. One column with the id from the IN Clause and another column with a batch id that I generate on the fly.
Before you select you shove your ids into the table with a given batch id.
Then you just replace your original queries IN clause with a INNER JOIN matching on your ids table WHERE batch_id equals your current batch. After your done your delete the entries for you batch.
执行此操作的标准方法是(如果您使用 Spring JDBC)是使用 org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate 类。
使用此类,可以将 List 定义为 SQL 参数并使用 NamedParameterJdbcTemplate 来替换命名参数。例如:
The standard way to do this is (if you are using Spring JDBC) is to use the org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate class.
Using this class, it is possible to define a List as your SQL parameter and use the NamedParameterJdbcTemplate to replace a named parameter. For example:
我通过使用尽可能多的
?
构建 SQL 字符串来解决这个问题,因为我有要查找的值。首先,我搜索了可以传递到语句中的数组类型,但所有 JDBC 数组类型都是特定于供应商的。所以我保留了多个
?
。I solved this by constructing the SQL string with as many
?
as I have values to look for.First I searched for an array type I can pass into the statement, but all JDBC array types are vendor specific. So I stayed with the multiple
?
.我从 docs.spring(19.7 .3)
希望这可以帮助你。
I got the answer from docs.spring(19.7.3)
Hope this can help you.
AFAIK,JDBC 中没有标准支持将集合作为参数处理。如果您可以传入一个列表并且该列表将被扩展,那就太好了。
Spring 的 JDBC 访问支持将集合作为参数传递。您可以看看这是如何完成的,以获得安全编码的灵感。
请参阅 自动扩展集合作为 JDBC 参数
(本文首先讨论 Hibernate,然后继续讨论 JDBC。)
AFAIK, there is no standard support in JDBC for handling Collections as parameters. It would be great if you could just pass in a List and that would be expanded.
Spring's JDBC access supports passing collections as parameters. You could look at how this is done for inspiration on coding this securely.
See Auto-expanding collections as JDBC parameters
(The article first discusses Hibernate, then goes on to discuss JDBC.)
看看我的尝试,它成功了,据说列表大小有潜在的限制。
List l = Arrays.asList(new Integer[]{12496,12497,12498,12499});
映射参数 = Collections.singletonMap("goodsid",l);
See my trial and It success,It is said that the list size has potential limitation.
List l = Arrays.asList(new Integer[]{12496,12497,12498,12499});
Map param = Collections.singletonMap("goodsid",l);
我们可以使用不同的替代方法。
此处查看有关这些内容的更多详细信息。
There are different alternative approaches that we can use.
Check more details about these here.
sormula 使这一切变得简单(参见示例 4):
sormula makes this simple (see Example 4):
我能想到的一种方法是使用 java.sql.PreparedStatement 和一些陪审团操纵
PreparedStatement preparedStmt = conn.prepareStatement("SELECT * FROM MYTABLE WHERE MYCOL in (?)");
...然后...
preparedStmt.setString(1, [你的字符串参数]);
http://java.sun.com/docs/books/教程/jdbc/basics/prepared.html
One way i can think of is to use the java.sql.PreparedStatement and a bit of jury rigging
PreparedStatement preparedStmt = conn.prepareStatement("SELECT * FROM MYTABLE WHERE MYCOL in (?)");
... and then ...
preparedStmt.setString(1, [your stringged params]);
http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html