IN 子句中带有参数列表的PreparedStatement
如何在执行查询时为 JDBC 中的 preparedStatement 中的 in 子句设置值。
示例:
connection.prepareStatement("Select * from test where field in (?)");
如果这个子句可以保存多个值,我该怎么做。有时我事先知道参数列表,有时我事先不知道。此案如何处理?
How to set value for in clause in a preparedStatement in JDBC while executing a query.
Example:
connection.prepareStatement("Select * from test where field in (?)");
If this in-clause can hold multiple values how can I do it. Sometimes I know the list of parameters beforehand or sometimes I don't know beforehand. How to handle this case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
我要做的就是添加一个“?”对于每个可能的值。
替代使用
StringBuilder
(这是十多年前的原始答案)然后愉快地设置参数
What I do is to add a "?" for each possible value.
Alternative using
StringBuilder
(which was the original answer 10+ years ago)And then happily set the params
您可以使用下面的 javadoc 中提到的 setArray 方法:
http://docs.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html#setArray(int, java.sql.Array)
代码
:
You could use
setArray
method as mentioned in the javadoc below:http://docs.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html#setArray(int, java.sql.Array)
Code:
您不能将查询中的
?
替换为任意数量的值。每个?
仅是单个值的占位符。要支持任意数量的值,您必须动态构建一个包含?, ?, ?, ... , ?
的字符串,其中问号的数量与值的数量相同你想要在你的in
子句中。You can't replace
?
in your query with an arbitrary number of values. Each?
is a placeholder for a single value only. To support an arbitrary number of values, you'll have to dynamically build a string containing?, ?, ?, ... , ?
with the number of question marks being the same as the number of values you want in yourin
clause.您不想将PreparedStatment与使用IN子句的动态查询一起使用,至少您确定您始终低于5个变量或类似的小值,但即使这样,我认为这是一个坏主意(不可怕,但很糟糕)。由于元素数量很大,情况会更糟(而且很糟糕)。
想象一下你的 IN 子句中有成百上千种可能性:
这会适得其反,你会损失性能和内存,因为每次新请求时都会进行缓存,而PreparedStatement不仅仅是为了 SQL 注入,它还关乎性能。在这种情况下,Statement 更好。
你的池有PreparedStatment的限制(默认为-1,但你必须限制它),你将达到这个限制!如果没有限制或限制非常大,则存在内存泄漏的风险,在极端情况下还会出现 OutofMemory 错误。因此,如果它是供 3 个用户使用的小型个人项目,那么这并不引人注目,但如果您在一家大公司,并且您的应用程序被数千人和数百万个请求使用,那么您不希望出现这种情况。
一些阅读。
IBM:使用准备时的内存利用率注意事项语句缓存
You don't want use PreparedStatment with dynamic queries using IN clause at least your sure you're always under 5 variable or a small value like that but even like that I think it's a bad idea ( not terrible, but bad ). As the number of elements is large, it will be worse ( and terrible ).
Imagine hundred or thousand possibilities in your IN clause :
It's counter-productive, you lost performance and memory because you cache every time a new request, and PreparedStatement are not just for SQL injection, it's about performance. In this case, Statement is better.
Your pool have a limit of PreparedStatment ( -1 defaut but you must limit it ), and you will reach this limit ! and if you have no limit or very large limit you have some risk of memory leak, and in extreme case OutofMemory errors. So if it's for your small personnal project used by 3 users it's not dramatic, but you don't want that if you're in a big company and that you're app is used by thousand people and million request.
Some reading.
IBM : Memory utilization considerations when using prepared statement caching
你需要jdbc4然后你可以使用setArray!
就我而言,它不起作用,因为 postgres 中的 UUID 数据类型似乎仍然有其弱点,但对于通常的类型它起作用。
当然,将 $VALUETYPE 和 myValuesAsArray 替换为正确的值。
备注以下标记注释:
您的数据库和驱动程序需要支持此功能!我尝试过 Postgres 9.4,但我认为这已经在之前介绍过了。您需要 jdbc 4 驱动程序,否则 setArray 将不可用。我使用了 Spring Boot 附带的 postgresql 9.4-1201-jdbc41 驱动程序
You need jdbc4 then you can use setArray!
In my case it didn't worked, as the UUID Datatype in postgres seems to still have its weak spots, but for the usual types it works.
Of course replace $VALUETYPE and myValuesAsArray with the correct values.
Remark following Marks comment:
Your database and the driver needs to support this! I tried Postgres 9.4 but I think this has been introduced earlier. You need a jdbc 4 driver, otherwise setArray won't be available. I used the postgresql 9.4-1201-jdbc41 driver that ships with spring boot
目前,MySQL 不允许在一个方法调用中设置多个值。
所以你必须把它置于你自己的控制之下。我通常为预定义数量的参数创建一个准备好的语句,然后根据需要添加尽可能多的批次。
如果您不喜欢在没有更多参数时设置 NULL,则可以修改代码以构建两个查询和两个准备好的语句。第一个是相同的,但第二个声明是余数(模数)。
在此特定示例中,一个查询将包含 10 个参数,另一个查询将包含 8 个参数。您必须为第一个查询添加 3 个批次(前 30 个参数),然后为第二个查询添加一个批次(8 个参数)。
Currently, MySQL doesn't allow to set multiple values in one method call.
So you have to have it under your own control. I usually create one prepared statement for predefined number of parameters, then I add as many batches as I need.
If you don't like to set NULL when no more parameters left, you can modify code to build two queries and two prepared statements. First one is the same, but second statement for the remainder (modulus).
In this particular example that would be one query for 10 params and one for 8 params. You will have to add 3 batches for the first query (first 30 params) then one batch for the second query (8 params).
您可以做的是,一旦您知道需要在 IN 子句中放入多少个值,就可以通过简单的 for 循环动态构建选择字符串(“IN (?)”部分)。然后您可以实例化PreparedStatement。
What you can do is dynamically build the select string (the 'IN (?)' part) by a simple for loop as soon as you know how many values you need to put inside the IN clause. You can then instantiate the PreparedStatement.
您可以使用:
然后:
示例:
You can use :
Then :
Exemple :
尝试使用此代码
try with this code
许多数据库都有临时表的概念,即使假设您没有临时表,您也可以始终生成一个具有唯一名称的临时表,并在完成后将其删除。虽然创建和删除表的开销很大,但这对于非常大的操作或将数据库用作本地文件或内存中的数据库(SQLite)的情况可能是合理的。
我正在处理的一个示例(使用 Java/SqlLite):
请注意,我的表使用的字段是动态创建的。
如果您能够重用该表,这会更加有效。
Many DBs have a concept of a temporary table, even assuming you don't have a temporary table you can always generate one with a unique name and drop it when you are done. While the overhead of creating and dropping a table is large, this may be reasonable for very large operations, or in cases where you are using the database as a local file or in memory (SQLite).
An example from something I am in the middle of (using Java/SqlLite):
Note that the fields used by my table are created dynamically.
This would be even more efficient if you are able to reuse the table.
公共静态无效主(字符串arg []){
public static void main(String arg[]) {