在最近的项目工作中,对于mybatis的sql动态判断需要学习。所以在这里记录一下学习的过程与心得。
前言
mybatis的动态sql拼接让很多复杂业务的处理变得简单化,开发人员只需要在xml文件中直接编写sql语句即可。再使用框架提供的方法,即可动态生成sql语句所需要的条件。但是在工作过程中。mybatis的if条件判断用法也需要一些技巧。
一、if判断语句过滤不同参数的处理
1.数字类型
1 如果参数为数字类型的时,且没有特殊需求的情况只需要判断是否为null即可。
<if test="id != null"></if>
2 如果有特殊需求,例如判断是否大于某个数的时候才行。只需要加上对应的条件判断即可
<if test='id != null and id > 28'></if>
3 mybatis对于这种大于小于等等还有另一种形式。
<if test='id != null and id gt 28'></if>
对应关系:
写法 | 对应 |
---|---|
gt | > |
gte | >= |
lt | <(会报错 相关联的 "test" 属性值不能包含 '<' 字符) |
lte | <=(会报错 相关联的 "test" 属性值不能包含 '<' 字符) |
2.字符串类型
1 如果不需要过滤空串的情况 仅仅判断null即可
<if test="username != null"></if>
2 如果需要过滤空串,添加空串判断即可,写法不支持 &&,所以这里用 and和or来做逻辑与或的判断
<if test="username != null and '' != username"></if> 或者 <if test="username != null and '' neq username"></if>
3 如果判断字符串是否以某个字符开头,结尾等。直接调用String的对应方法即可
<if test="username != null and username.indexOf('ji') == 0"> </if>
<!-- 是否以什么开头 -->
<if test="username != null and username.indexOf('ji') >= 0"> </if><!-- 是否包含某字符 -->
<if test="username != null and username.lastIndexOf('ji') > 0"></if><!-- 是否以什么结尾 -->
4 是否为特定字符串,某些业务需要判断
<if test="username != null and 'hello' == username"></if> 或者<if test="username != null and 'hello' eq username"></if>
5 这里有个需要注意的点:如果参数类型是字符串的话,这么写是没问题的。
<if test="username != null and 'hello' == username"></if>
但是参数类型为非字符串类型的时候就需要写成,否则可能会挂
<if test="username != null and 'hello'.toString() == username.toString()"></if>
6 if的条件判断test是支持对象自身方法调用的,即使是自己写的方法,可以自己尝试。当然下面会有例子。
例如:里面可以用‘xxxx’.equals(xxxx) 字符串的比较两个字符串方法,xxxx.indexOf('ss') 判断字符串里面是否包含某个字符等等
7 判断list是否为空
上面说过,if条件判断可以直接调用对象自身的方法进行逻辑判断,所以list判空。可以调用.size()>0或者.isEmpty()
<if test="userList != null and userList.isEmpty()"></if> , <if test="userList != null and userList.size()>0"></if>
二、测试与结果
1.数字类型
仅作null判断:
<!--if 标签使用类似html的C标签的if -->
<select id="selectUseIf" parameterType="com.soft.test.model.DynamicTestModel" resultMap="userMap">
select * from t_user where 1=1
<if test='id != null'>
and id=#{id}
</if>
</select>
当id不为null的时候打印的log
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and id=?
DEBUG [main] - ==> Parameters: 28(Integer)
DEBUG [main] - <== Total: 1
当id为null的时候 打印的log
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 1
两项对比,可以看出id=?这个条件随着传入参数id的变化而变化。
接下来测试下面这几种对应关系。
写法 | 对应 |
---|---|
gt | > |
gte | >= |
lt | <(会报错 相关联的 "test" 属性值不能包含 '<' 字符) |
lte | <=(会报错 相关联的 "test" 属性值不能包含 '<' 字符) |
gt
<if test='id != null and id gt 27 '>
参数 id=25
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
参数 id=28
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and id=?
DEBUG [main] - ==> Parameters: 28(Integer)
>=
<if test='id != null and id >= 28 '>
参数 id=28
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and id=?
DEBUG [main] - ==> Parameters: 28(Integer)
参数 id=27
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
gte
<if test='id != null and id gte 28 '>
参数 id=28
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and id=?
DEBUG [main] - ==> Parameters: 28(Integer)
参数 id=27
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
使用 <和<=直接报错,说明"test" 属性值不能包含 '<' 字符 看来只能用 lt或者lte了
lt
<if test='id != null and id lt 28 '>
参数 id=28
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
参数 id=27
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and id=?
DEBUG [main] - ==> Parameters: 27(Integer)
lte
<if test='id != null and id lte 28 '>
参数 id=28
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and id=?
DEBUG [main] - ==> Parameters: 28(Integer)
参数 id=29
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
2.字符串类型
过滤空串
<select id="selectUseIf" parameterType="com.soft.test.model.DynamicTestModel" resultMap="userMap">
select * from t_user where 1=1
<if test="username != null and '' != username ">
and username=#{username}
</if>
</select>
!=
username=“xiao”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiao(String)
username=“”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
neq
<if test="username != null and '' neq username ">
username=“xiao”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiao(String)
username=“”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
各个逻辑与或的判断,and上面已经弄过了,这里弄or || 两种条件
<if test="'xiaohong' eq username or 'xiao' eq username ">
or
username=“xiao”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiao(String)
username=“xiaohong”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiaohong(String)
username=“xiaofang”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
||
username=“xiao”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiao(String)
username=“xiaohong”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiaohong(String)
username=“xiaofang”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1
DEBUG [main] - ==> Parameters:
indexOf()或者lastIndexOf()用于判断是否包含某个特定字符
<if test="username != null and username.indexOf('xiao')==0">
username=“xiao”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiao(String)
username=“xiaofang”
DEBUG [main] - ==> Preparing: select * from t_user where 1=1 and username=?
DEBUG [main] - ==> Parameters: xiaofang(String)
其他两个没什么大不同的。自行测试。
判断是否是某个字符
<if test="'xiaohong' eq username">
username=“xiaohong”
==> Preparing: select * from t_user where 1=1 and username=?
==> Parameters: xiaohong(String)
username=“xiaofang”
==> Preparing: select * from t_user where 1=1
==> Parameters:
mybatis的if条件判断语句可以直接执行对象的方法。下面自己写一个方法,在if里面试试。
自己定义一个类,里面一个方法用于条件判断用。
public class DynamicSql1Model {
public boolean getMySelfMethod(){
return true;
}
}
该类作为一个属性放入到model中 仅仅贴出部分代码
public class DynamicSqlModel {
private int id;
private String username;
private String password;
private Date createDate;
private List<String> list;
private Map<String,Object> mapParam;
private DynamicSql1Model dynamicSql1Model;
xml中引用该model的方法
<if test="dynamicSql1Model.getMySelfMethod()">
开始测试
DynamicSqlModel user = new DynamicSqlModel();
user.setUsername("xiaofang");
user.setPassword("123456");
user.setCreateDate(new Date());
DynamicSql1Model dynamicSqlModel = new DynamicSql1Model();
user.setDynamicSql1Model(dynamicSqlModel);
dao.selectUseIf(user);
现在返回结果
现在方法的返回值为true
==> Preparing: select * from t_user where 1=1 and username=?
==> Parameters: xiaofang(String)
方法返回值修改为false
==> Preparing: select * from t_user where 1=1
==> Parameters:
可以看出完全可以使用自定义的方法进行if条件控制。通过该特性可以干一些特俗业务的事情。自己体会。
本篇说的主要是if条件判断动态控制sql。可以看出有弊端。因为if条件不满足的时候sql会变成
select * from t_user where 所以我在条件后面加了个 1=1 但是这是不符合逻辑的。下节介绍where以及其他标签用于动态sql。