MyBatis 中的列表 'IN' 子句
Lists in MyBatis 'IN' clause
如何将整数列表传递给 MyBatis XML,以便在我的 MySQL 查询的 in 子句中使用?
我在 mapper-xml
文件中使用 Java 7、MySQL 5.6 DB 和 MyBatis 3.0.4 进行查询。
目前,我正在将这个整数列表转换为字符串,并使用字符串替换(${}
运算符)将值放入 'IN' 子句中 - 虽然它按预期工作,但这方法使参数容易受到注入攻击。
我试过使用 <foreach>
元素,但我无法弄清楚要指定哪些属性。
下面是一个示例 Java 代码:
public List<Stripper> getStripperDetails(String club, List<Integer> stripperIds) {
Map<String, Object> input = new HashMap<>();
input.put("club", club);
input.put("stripperIds", stripperIds);
return stripClubMapper.getStripperDetails(input);
}
映射器xml:
<select id="getStripperDetails" parameterType="java.util.HashMap" resultMap="StripperMap">
SELECT STRIPPER_ID, STAGE_NAME, REAL_NAME, CLUB FROM EXOTIC_DANCERS WHERE CLUB = #{club} AND STRIPPER_ID IN
<foreach item="item" index="index" collection="stripperIds" open="(" separator="," close=")">
#{index}
</foreach>
</select>
我无法弄清楚要为 <foreach>
元素指定哪些属性 - 我将 运行 保存到 #{index} 处的值的 NullPointerException 中。
你能帮我理解 <foreach>
元素的正确用法吗?
编辑:
@10086 ,
下面是堆栈跟踪:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.NullPointerException
### The error may involve com.stripclub.mapper.stripClubMapper.getStripperDetails-Inline
### The error occurred while setting parameters
### Cause: java.lang.NullPointerException
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:67) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:345) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at com.sun.proxy.$Proxy208.selectList(Unknown Source) ~[na:na]
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:193) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at org.apache.ibatis.binding.MapperMethod.executeForList(MapperMethod.java:85) ~[mybatis-3.0.4.jar:3.0.4]
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:65) ~[mybatis-3.0.4.jar:3.0.4]
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:38) ~[mybatis-3.0.4.jar:3.0.4]
at com.sun.proxy.$Proxy209.getTransactionIds(Unknown Source) ~[na:na]
你的xml应该是这样的:
<foreach item="item" index="index" collection="stripperIds" open="(" separator="," close=")">
#{item}
</foreach>
当使用 Map(或 Map.Entry 对象的集合)时,index 将是键对象,item 将是值对象。
详情可参考here。您将对属性有深入的了解。
您输入的是一张地图。所以你需要在直接调用 stripperIds 之前从输入解析 stripperIds。
当与列表一起使用时,item 属性指定的值应该在 foreach 标签内使用。使用如下:
<foreach item="sId" collection="stripperIds" separator="," open="(" close=")">
#{sId}
</foreach>
使用列表时,索引属性不是必需的。请参阅 MyBatis 文档部分以获取更多信息,或查看 DTD - http://mybatis.org/dtd/mybatis-3-mapper.dtd 以获取有关参数的更多信息:
<!ELEMENT foreach (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
<!ATTLIST foreach
collection CDATA #REQUIRED
item CDATA #IMPLIED
index CDATA #IMPLIED
open CDATA #IMPLIED
close CDATA #IMPLIED
separator CDATA #IMPLIED
>
此外,对象列表可以在 foreach 中访问,如下所示。您通常会将其用于 INSERT/UPDATE 语句:
示例 bean:
public class StripperBean {
public StripperBean(int stripperID, String stripperName, String realName) {
this.stripperID = stripperID;
this.stripperName = stripperName;
this.realName = realName;
}
private int stripperID;
private String stripperName;
private String realName;
public int getStripperID() {
return stripperID;
}
public void setStripperID(int stripperID) {
this.stripperID = stripperID;
}
public String getStripperName() {
return stripperName;
}
public void setStripperName(String stripperName) {
this.stripperName = stripperName;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
}
在您的实施中:
Map<String, Object> input = new HashMap<>();
input.put("club", club);
List<StripperBean> strippers = new ArrayList<>();
strippers.add(new StripperBean(1,"Ashley", "Jean Grey"));
strippers.add(new StripperBean(2,"Candice","Diana Prince"));
strippers.add(new StripperBean(3,"Cristal","Lara Croft"));
input.put("strippers", strippers);
return stripClubMapper.saveStripperDetails(input);
在映射器中 xml :
<insert id="saveStripperDetails">
INSERT INTO EXOTIC_DANCERS (STRIPPER_ID, STAGE_NAME, REAL_NAME)
VALUES
<foreach item="stripper" collection="input" separator=",">
(#{stripper.stripperID},
#{stripper.stripperName},
#{stripper.realName})
</foreach>
</select>
顺便问个好问题 :)
使用注释应该更容易
@Select({
"<script>", "select", " * ", "FROM TABLE",
"WHERE CONDITION IN " +
"<foreach item='item' index='index' collection='list' open='(' separator=',' close=')'> #{item} </foreach>" +
"</script>" })
@Results({ })
List<POJO> selectByKeys(@Param("list") List<String> ids);
如何将整数列表传递给 MyBatis XML,以便在我的 MySQL 查询的 in 子句中使用?
我在 mapper-xml
文件中使用 Java 7、MySQL 5.6 DB 和 MyBatis 3.0.4 进行查询。
目前,我正在将这个整数列表转换为字符串,并使用字符串替换(${}
运算符)将值放入 'IN' 子句中 - 虽然它按预期工作,但这方法使参数容易受到注入攻击。
我试过使用 <foreach>
元素,但我无法弄清楚要指定哪些属性。
下面是一个示例 Java 代码:
public List<Stripper> getStripperDetails(String club, List<Integer> stripperIds) {
Map<String, Object> input = new HashMap<>();
input.put("club", club);
input.put("stripperIds", stripperIds);
return stripClubMapper.getStripperDetails(input);
}
映射器xml:
<select id="getStripperDetails" parameterType="java.util.HashMap" resultMap="StripperMap">
SELECT STRIPPER_ID, STAGE_NAME, REAL_NAME, CLUB FROM EXOTIC_DANCERS WHERE CLUB = #{club} AND STRIPPER_ID IN
<foreach item="item" index="index" collection="stripperIds" open="(" separator="," close=")">
#{index}
</foreach>
</select>
我无法弄清楚要为 <foreach>
元素指定哪些属性 - 我将 运行 保存到 #{index} 处的值的 NullPointerException 中。
你能帮我理解 <foreach>
元素的正确用法吗?
编辑:
@10086 ,
下面是堆栈跟踪:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.NullPointerException
### The error may involve com.stripclub.mapper.stripClubMapper.getStripperDetails-Inline
### The error occurred while setting parameters
### Cause: java.lang.NullPointerException
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:67) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:345) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at com.sun.proxy.$Proxy208.selectList(Unknown Source) ~[na:na]
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:193) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at org.apache.ibatis.binding.MapperMethod.executeForList(MapperMethod.java:85) ~[mybatis-3.0.4.jar:3.0.4]
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:65) ~[mybatis-3.0.4.jar:3.0.4]
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:38) ~[mybatis-3.0.4.jar:3.0.4]
at com.sun.proxy.$Proxy209.getTransactionIds(Unknown Source) ~[na:na]
你的xml应该是这样的:
<foreach item="item" index="index" collection="stripperIds" open="(" separator="," close=")">
#{item}
</foreach>
当使用 Map(或 Map.Entry 对象的集合)时,index 将是键对象,item 将是值对象。
详情可参考here。您将对属性有深入的了解。
您输入的是一张地图。所以你需要在直接调用 stripperIds 之前从输入解析 stripperIds。
当与列表一起使用时,item 属性指定的值应该在 foreach 标签内使用。使用如下:
<foreach item="sId" collection="stripperIds" separator="," open="(" close=")">
#{sId}
</foreach>
使用列表时,索引属性不是必需的。请参阅 MyBatis 文档部分以获取更多信息,或查看 DTD - http://mybatis.org/dtd/mybatis-3-mapper.dtd 以获取有关参数的更多信息:
<!ELEMENT foreach (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
<!ATTLIST foreach
collection CDATA #REQUIRED
item CDATA #IMPLIED
index CDATA #IMPLIED
open CDATA #IMPLIED
close CDATA #IMPLIED
separator CDATA #IMPLIED
>
此外,对象列表可以在 foreach 中访问,如下所示。您通常会将其用于 INSERT/UPDATE 语句:
示例 bean:
public class StripperBean {
public StripperBean(int stripperID, String stripperName, String realName) {
this.stripperID = stripperID;
this.stripperName = stripperName;
this.realName = realName;
}
private int stripperID;
private String stripperName;
private String realName;
public int getStripperID() {
return stripperID;
}
public void setStripperID(int stripperID) {
this.stripperID = stripperID;
}
public String getStripperName() {
return stripperName;
}
public void setStripperName(String stripperName) {
this.stripperName = stripperName;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
}
在您的实施中:
Map<String, Object> input = new HashMap<>();
input.put("club", club);
List<StripperBean> strippers = new ArrayList<>();
strippers.add(new StripperBean(1,"Ashley", "Jean Grey"));
strippers.add(new StripperBean(2,"Candice","Diana Prince"));
strippers.add(new StripperBean(3,"Cristal","Lara Croft"));
input.put("strippers", strippers);
return stripClubMapper.saveStripperDetails(input);
在映射器中 xml :
<insert id="saveStripperDetails">
INSERT INTO EXOTIC_DANCERS (STRIPPER_ID, STAGE_NAME, REAL_NAME)
VALUES
<foreach item="stripper" collection="input" separator=",">
(#{stripper.stripperID},
#{stripper.stripperName},
#{stripper.realName})
</foreach>
</select>
顺便问个好问题 :)
使用注释应该更容易
@Select({
"<script>", "select", " * ", "FROM TABLE",
"WHERE CONDITION IN " +
"<foreach item='item' index='index' collection='list' open='(' separator=',' close=')'> #{item} </foreach>" +
"</script>" })
@Results({ })
List<POJO> selectByKeys(@Param("list") List<String> ids);