如何使用 iBatis (myBatis) 的注释进行 IN 查询?
我们只想在 MyBatis 中使用注释;我们确实在努力避免使用 xml。我们尝试使用“IN”子句:
@Select("SELECT * FROM blog WHERE id IN (#{ids})")
List<Blog> selectBlogs(int[] ids);
MyBatis 似乎无法挑选出整数数组并将其放入结果查询中。它似乎“温和地失败”,我们没有得到任何结果。
看起来我们可以使用 XML 映射来完成此任务,但我们确实希望避免这种情况。是否有正确的注释语法?
We'd like to use only annotations with MyBatis; we're really trying to avoid xml. We're trying to use an "IN" clause:
@Select("SELECT * FROM blog WHERE id IN (#{ids})")
List<Blog> selectBlogs(int[] ids);
MyBatis doesn't seem able to pick out the array of ints and put those into the resulting query. It seems to "fail softly" and we get no results back.
It looks like we could accomplish this using XML mappings, but we'd really like to avoid that. Is there a correct annotation syntax for this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我相信答案与 这个问题。您可以通过执行以下操作在注释中使用 myBatis 动态 SQL:
元素启用注释的动态 SQL 解析和执行。它必须是查询字符串的第一个内容。它前面不能有任何东西,甚至是空白。
请注意,您可以在各种 XML 脚本标记中使用的变量遵循与常规查询相同的命名约定,因此,如果您想使用“param1”、“param2”等以外的名称引用方法参数...需要在每个参数前面加上 @Param 注释。
I believe the answer is the same as is given in this question. You can use myBatis Dynamic SQL in your annotations by doing the following:
The
<script>
element enables dynamic SQL parsing and execution for the annotation. It must be very first content of the query string. Nothing must be in front of it, not even white space.Note that the variables that you can use in the various XML script tags follow the same naming conventions as regular queries, so if you want to refer to your method arguments using names other than "param1", "param2", etc... you need to prefix each argument with an @Param annotation.
我相信这是 jdbc 准备好的语句的细微差别,而不是 MyBatis。 此处有一个链接解释了此问题并提供了各种解决方案。不幸的是,这些解决方案都不适合您的应用程序,但是,它仍然是了解准备好的语句与“IN”子句相关的限制的好读物。可以在特定于数据库的方面找到解决方案(可能不是最佳的)。例如,在 postgresql 中,可以使用:
“ANY”与“IN”相同,而“::int[]”是将参数类型转换为整数数组。输入到语句中的参数应该类似于:
I believe this is a nuance of jdbc's prepared statements and not MyBatis. There is a link here that explains this problem and offers various solutions. Unfortunately, none of these solutions are viable for your application, however, its still a good read to understand the limitations of prepared statements with regards to an "IN" clause. A solution (maybe suboptimal) can be found on the DB-specific side of things. For example, in postgresql, one could use:
"ANY" is the same as "IN" and "::int[]" is type casting the argument into an array of ints. The argument that is fed into the statement should look something like:
对这个主题进行了一些研究。
@Select("")
中。然而,在java注解中写xml是相当不优雅的。考虑这个@Select("")
pstm.setString(index, "1,2,3,4")
会让你的 SQL 像这样select name from sometable where id in ('1,2,3,4')
。 Mysql 会将字符'1,2,3,4'
转换为数字1
。查看mybatis的动态sql机制,它是通过
SqlNode.apply(DynamicContext)
实现的。但是,没有注释的 @Select 将不会通过
DynamicContext
传递参数,另请参阅
org.apache.ibatis.scripting.xmltags。 XMLLanguageDriver
org.apache.ibatis.scripting.xmltags.DynamicSqlSource
org.apache.ibatis.scripting.xmltags.RawSqlSource
所以,
DynamicSqlSource
。但是,你仍然必须到处写\"
。我的项目采用解决方案 3,代码如下:
以及用法:
Had some research on this topic.
@Select("<script>...</script>")
. However, writing xml in java annotation is quite ungraceful. think about this@Select("<script>select name from sometable where id in <foreach collection=\"items\" item=\"item\" seperator=\",\" open=\"(\" close=\")\">${item}</script>")
@SelectProvider
works fine. But it's a little complicated to read.pstm.setString(index, "1,2,3,4")
will let your SQL like thisselect name from sometable where id in ('1,2,3,4')
. Mysql will convert chars'1,2,3,4'
to number1
.Look in to mybatis dynamic sql mechanism, it has been implemented by
SqlNode.apply(DynamicContext)
. However, @Select without<script></script>
annotation will not pass parameter viaDynamicContext
see also
org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
org.apache.ibatis.scripting.xmltags.DynamicSqlSource
org.apache.ibatis.scripting.xmltags.RawSqlSource
So,
DynamicSqlSource
. However, you still have to write\"
everywhere.My project take solution 3 and here's the code:
And the usage:
我在代码中做了一个小技巧。
我在 SqlMapper 中使用了这个 MyHandler :
它现在可以工作了:)
我希望这会对某人有所帮助。
叶夫根尼
I've made a small trick in my code.
And I used this MyHandler in SqlMapper :
It works now :)
I hope this will help someone.
Evgeny
其他选项可以是
Other option can be
在我的项目中,我们已经在使用 Google Guava,所以一个快速的捷径是。
In my project, we are already using Google Guava, so a quick shortcut is.
在 Oracle 中,我使用 的变体Tom Kyte 的分词器 用于处理未知的列表大小(考虑到 Oracle 对 IN 子句的 1k 限制以及执行多个 IN 来绕过它的加剧)。这是针对 varchar2 的,但它可以针对数字进行定制(或者您可以仅依赖 Oracle 知道 '1' = 1 /shudder)。
假设您传递或执行 myBatis 咒语以字符串形式获取 ids ,并使用它:
代码:
In Oracle, I use a variant of Tom Kyte's tokenizer to handle unknown list sizes (given Oracle's 1k limit on an IN clause and the aggravation of doing multiple INs to get around it). This is for varchar2, but it can be tailored for numbers (or you could just rely on Oracle knowing that '1' = 1 /shudder).
Assuming you pass or perform myBatis incantations to get
ids
as a String, to use it:The code:
您可以使用自定义类型处理程序来执行此操作。例如:
在 MyBatis 配置中注册以下类型处理程序(或在注释中指定):
然后您可以像这样使用它们
但是,这对 MySQL 不起作用,因为 MySQL 连接器不支持
setArray()
用于准备好的语句。MySQL 的一个可能的解决方法是使用
FIND_IN_SET
而不是IN
:并且您的类型处理程序变为:
注意:我不知道
FIND_IN_SET
的性能>,所以测试一下它是否重要You could use a custom type handler to do this. For example:
Register the following type handler in your MyBatis config (or specify in your annotation):
You can then use them like this
However, this will not work for MySQL, because the MySQL connector does not support
setArray()
for prepared statements.A possible workaround for MySQL is to use
FIND_IN_SET
instead ofIN
:And your type handler becomes:
Note: I don't know the performance of
FIND_IN_SET
, so test this if it is important我是用 postgresql 完成的。
ANY
的工作方式与IN
类似。上面的代码使用的是
groovy
,但可以通过将单引号替换为双引号来转换为java
。I had done this with
postgresql
.ANY
works like theIN
.Code above is using
groovy
but can be converted intojava
by replacing the single quotes into double.