假定一张用户表,要通过姓名(userName)模糊以及职位id(userRole)筛选显示所有符合条件的信息。普通sql语句的写法是:
select * from user
where userName CONCAT('%',#{userName},'%')
and userRole ={userRole}
有这样一种情况,在用户进行多条件查询数据或更新数据的时候,可能会不进行一项或多项参数的传值,比如userName不进行传参,那么执行的时候上述语句实际执行的是
select * from user where userName CONCAT(’%’,null,’%’) and userRole ={userRole}
模糊查询名字中有null,职位id是xx的人,这样很显然查不出数据,达不到预期的设想。
解决方案:if+trim标签
上述语句可以优化为:
//省略代码
select * from user
<trim prefix="where" prefixOverrides="and">
<if test="userName!=null and userName !=''">
AND userName like CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=null">
AND userRole = #{userRole}
</if>
</trim>
//省略代码
这条语句的意思就是:如果userName不为null且不为空字符串,就执行这一部分语句,并在语句之前增加 ‘where’ 关键字,否则跳过。如果userRole不为null,就进行这一部分语句,并在语句之前增加 ‘where’ 关键字(如果之前的语句已经增加过了就不会再增加)。如果有上述内容中有多余的’and’关键字,就把它删除。
首先< if>< /if>标签的作用与在Java中一样,是进行一个判断,"test"属性就是要判断的条件,如果返回值为真,则进行标签内语句,否则跳过。
< trim>< /trim>标签则是对多余的sql语句进行动态的修改,prefix表示开头的信息,如果后面的if条件有返回值就会在开头加上,prefixOverrides表示结尾指定内容的忽略 suffix表示最后的固定结尾内容,在这条语句中没有使用到。
通过这样的修改,假设当传入的userName是null或者’’,userRole是1的时候,语句会动态的修改成
select * from user
where userRole =1
或者当传入的userName是"赵"而userRole是null的时候,语句会动态的修改成:
select * from user
where userRole =1
where userName like CONCAT(’%’,‘赵’,’%’)
又或者,当userName和userRole都是null,那么语句会动态的修改成:
select * from user
总的来说< trim>标签很强大,除了select ,update set也可以使用,就不赘述了。
< foreach>标签
需求:指定用户职位userRole(1-n个),获取这些用户角色下的用户列表信息
举例:select * from user where userRole in (2,3)
//省略代码
select * from user where userRole in
<foreach collection="array"
item="roleIds" open="(" separator="," close=")">
#{roleIds}
</foreach>
//省略代码
属性:
item:集合里每一个元素进行迭代时的别名
index:指定一个名称,代表每次迭代到的位置
collection:必须指定 。list、array、map-key
open:表示语句以什么来开始
separator:迭代之间以什么符号进行间隔
close:语句以什么结束
上述mapper方法对应的接口方法是
List<User> getUserByRoleId_foreach_array(Integer[] roleIds);
测试方法:
public void getUserByRoleId_foreach_array() {
SqlSession sqlSession = null;
List<User> userList = new ArrayList<>();
Integer[] roleIds = {1, 2};
try {
sqlSession = MyBatisUtils.getSQLSession();
userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(roleIds);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
for (User user : userList) {
logger.debug("user ===========> id: " + user.getId() +
", userName: " + user.getUserName() +
", userAddress: " + user.getAddress() +
", userRole: " + user.getUserRole());
}
}
上述代码中指定了迭代的类型(collection)是数组array,实际上迭代集合list也是基本一致的用法。
collection:map-key 这里迭代的是一个map,具体到map的key。
需求:指定用户职位userRole(1-n个),且性别(gender)是1的用户,获取这些用户列表信息
从需求可以看出实际上有两个限制条件,条件1是固定值,条件2是个集合。这样就可以考虑用map的方式进行迭代查询。
接口方法:
List<User> getUserByRoleId_foreach_map(Map<String,Object> roleMap);
mapper文件:
//省略代码
select * from user where gender=#{gender}
AND userRole IN
<foreach collection="userRole" item="roleMap"
open="(" separator="," close=")">
#{roleMap}
</foreach>
//省略代码
测试方法:
public void getUserByRoleId_foreach_map() {
SqlSession sqlSession = null;
Map<String,Object> roleMap = new HashMap<>();
List<Integer> roleList = new ArrayList<>();
roleList.add(2);
roleList.add(3);
roleMap.put("gender",1);
roleMap.put("userRole",roleList);
List<User> userList = new ArrayList<>();
try {
sqlSession = MyBatisUtils.getSQLSession();
userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_map(roleMap);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
logger.debug("getUserListByRoleIdTest userList.size : " + userList.size());
for (User user : userList) {
logger.debug("user ===========> id: " + user.getId() +
", userName: " + user.getUserName() +
", userAddress: " + user.getAddress() +
", userRole: " + user.getUserRole()+
", gender: " + user.getGender()
);
}
}
这里值得注意的就是用于存放userRole参数的list集合的key名要跟mapper映射文件里的collection的值保持一致。用于存放所有参数的map集合的key要跟mapper映射文件里的item的值以及#{参数名}保持一致。
到这里,Mybatis的使用系列就告一段落,该吃午饭了。