参考:
既然琴瑟起 https://www.cnblogs.com/qiankun-site/p/5762380.html
V青山绿水 http://www.cnblogs.com/ruiati/p/6410339.html
foreach标签主要用于构建in条件,它可以在sql中对集合进行迭代,通常可以将之用到批量删除、添加等操作中,示例如下:
delete from user where id in
#{id}
我们假如说参数为---- int[] ids = {1,2,3,4,5} ----那么打印之后的SQL为:delete form user where id in (1,2,3,4,5)
foreach元素的属性主要有 item,index,collection,open,separator,close。
item表示集合中每一个元素进行迭代时的别名,
index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,
open表示该语句以什么开始,
separator表示在每次进行迭代之间以什么符号作为分隔 符,
close表示以什么结束。
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况:
1. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3. 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可
1、传入List
public List findUserListByIdList(List idList) {
return getSqlSession().selectList("com.liulanghan.findUserListByIdList", idList);
}
对应mapper:
即单独传入list时,foreach中的collection必须是list,不管变量的具体名称是什么。比如这里变量名为idList, collection却是list。
2、传入数组
public List findUserListByIdList(int[] ids) {
return getSqlSession().selectList("com.liulanghan.findUserListByIdList", ids);
}
对应mapper:
单独传入数组时,foreach中的collection必须是array,不管变量的具体名称是什么。比如这里变量名为ids,collection却是array
3、传入map
public boolean exists(Map map){
Object count = getSqlSession().selectOne("com.liulanghan.exists", map);
int totalCount = Integer.parseInt(count.toString());
return totalCount > 0 ? true : false;
}
对应mapper:
MAP中有list或array时,foreach中的collection必须是具体list或array的变量名。比如这里MAP含有一个名为idList的list,所以MAP中用idList取值,这点和单独传list或array时不太一样。
4 、 传入JAVA对象
public boolean findUserListByDTO(UserDTO userDTO){
Object count = getSqlSession().selectOne("com.liulanghan.exists", userDTO);
int totalCount = Integer.parseInt(count.toString());
return totalCount > 0 ? true : false;
}
对应mapper:
select id="findUserListByDTO" parameterType="UserDTO" resultType="java.lang.Integer">
SELECT COUNT(*) FROM USER user
and user.CODE = #{code}
and user.ID = #{id}
and user.ID in (
#{guard}
)
JAVA对象中有list或array时,foreach中的collection必须是具体list或array的变量名。比如这里UserDTO含有一个名为idList的list,所以UserDTO中用idList取值,这点和单独传list或array时不太一样。
6.取值
由上面可以看出,取值的时候用的是#{}。它具体的意思是告诉MyBatis创建一个预处理语句参数。
使用JDBC时,这样的一个参数在SQL中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:
// Similar JDBC code, NOT MyBatis…
String selectPerson = “SELECT * FROM PERSON WHERE ID=?”;
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);
可以看到这个写法比较简单,MyBatis为我们做了很多默认的事情,具体的写法应该如下:
#{property,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler,mode=OUT,resultMap=User}
上面sql语句对应字段的含义:
property:属性名,即代码传入的变量名。
javaType:该字段在JAVA中的类型,比如int。
jdbcType:该字段在JDBC中的类型,比如NUMERIC。
typeHandler:类型处理器
mode:参数类型为IN,OUT或INOUT参数
resultMap:结果。
还好,MyBatis比较体谅我们,一般我们只需写一个属性名即可,如#{id},其他的如javaType和typeHandlerMybatis会自动帮我们填好。可是这样有时也会出问题,比如出现CLOB字段时。
由于JAVA代码中的String类型对应的默认typeHandler为StringTypeHandler,当用String类型处理时,如果String长度超过一定长度,就会报如下错误:
setString can only process strings of less than 32766 chararacters
解决办法是指定该属性的typeHandler,如下:
#{message,typeHandler=org.apache.ibatis.type.ClobTypeHandler}
我们也可以自定义typeHandler来处理需要的数据,具体这里详述。
JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。这是JDBC的需要,而不是MyBatis的。一般不需要配置
mode、resultMap一般不需要,在写存储过程时会用到,这里不详述。
7.字符串替换
一般情况下,我们采用#{}取值,产生预处理语句,但是有时我们可能不希望Mybatis来帮我们预处理,比如ORDER BY时,可以
采用如下写法:
ORDER BY ${columnName}
这里MyBatis不会修改或转义字符串。而是直接拼接到SQL字符串后面。
重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你
不应该允许用户输入这些字段,或者通常自行转义并检查。