mybatis 动态参数及其 foreach collection使用
Mybatis里传参数入Mapper一般基于基本类型,Integer、String、List、Hashtable,然后以此构架foreach迭代动态sql。
1 2 3 4 5 6 7 8 |
<select id="findUserListByIdList" parameterType="java.util.ArrayList" resultType="User"> select * from user user <where> user.id in <foreach collection="listName" item="guard" index="index" separator="," open="(" separator="," close=")" > #{guard} </foreach> </where> </select> |
但是这种方法只针对一级引用,如果参数是Object,比如将下面的Page作为参数传入,其中的PageData已经put了一个名为listName的List。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Page { private PageData pd = new PageData(); } public class PageData extends HashMap<Object, Object> implements Map<Object, Object> { } List listName = new ArrayList(); Page page = new Page(); page.getPageData().put("listName", listName ); |
但是下面例子调用失败,mybatis无法辨认二级参数pd.listName是个List。
1 2 3 4 5 6 7 8 |
<select id="findUserListByIdList" parameterType="PageData" resultType="User"> select * from user user <where> user.id in <foreach collection="pd.listName" item="guard" index="index" separator="," open="(" separator="," close=")" > #{guard} </foreach> </where> </select> |
没找到直接解决办法,只能绕过foreach而采用String基本类型,尝试如下:
1 2 3 4 5 6 7 8 9 |
page.getPageData().put("listIdString", “1,2,3,4,5,6” ); <select id="findUserListByIdList" parameterType="PageData" resultType="User"> select * from user user <where> user.id in ( #{listIdString}) </where> </select> |
结果测试结果始终返回id为1的一个数据,而不是1,2,3,4,5,6六个数据。原因是带 #{} 的参数使用的是PreparedStatement,会有类型转换,最终注入sql的不是
1 |
user.ID in ( 1,2,3,4,5,6) |
而是加一层包装作为String注入:
1 |
user.ID in ( “1,2,3,4,5,6”) |
解决办法,使用 $ {} 参数,这样mybatis不会做任何预处理,直接作为String使用。
1 2 3 4 5 6 |
<select id="findUserListByIdList" parameterType="PageData" resultType="User"> select * from user user <where> user.id in ( ${listIdString}) </where> </select> |
1. 注意
但是在mybatis中,”${xxx}”这样格式的参数会直接参与sql编译,从而不能避免注入攻击。在涉及到动态表名和列名时,只能使用“${xxx}”这样的参数格式,所以,这样的参数需要我们在代码中手工进行处理来防止注入。
2. 参考
mybatis 传入参数及其 foreach collection的三种用法
https://stackoverflow.com/questions/11760074/mybatis-string-as-parameter