当mybatis
判断条件<if>
与单字符数字比较,会判断错误。大家是否踩过这个坑?
1.代码复现
先看这个例子:
//UserInfoTab 对象
@Data
public class UserInfoTab {
private Integer id;
private String userName;
private String userId;
...
}
mybatis 查询
<select id="selectByUserInfo" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_info_tab a
<where>
<if test="userId == '1' ">
and a.user_name = 'tianluoboy'
</if>
<if test="userId != '1' ">
and a.user_name != 'tianluoboy'
</if>
</where>
</select>
目前用户表的数据:
现在我的单元测试查询是这样的:
@Test
void testQueryUserInfo(){
List<UserInfoTab> userInfoTabList = userInfoTabDao.selectByUserInfo("1");
if (CollectionUtils.isEmpty(userInfoTabList)) {
userInfoTabList.forEach(System.out::println);
}
}
如果这个条件生效:
<if test="userId == '1' ">
and a.user_name = 'tianluoboy'
</if>
我应该查到tianluoboy
这条记录,但是事实查到的结果,却是:
也就是说<if test="userId == '1' ">
这个条件不生效。
2. 正确的使用方法
如果改成用双引号包着"1"
,或者用toString()
转换一下,则是可以正确查出来的:
<if test='userId == "1"'>
and a.user_name = 'tianluoboy'
</if>
<if test="userId == '1'.toString()">
and a.user_name = 'tianluoboy'
</if>
3. 原因解析
Mybatis 是使用OGNL表达式来解析的,'1'会解析为字符Character,一个字符Character和一个String 当然不相等,这就是为什么
<if test="userId == '1' ">
不生效。
大家有兴趣可以去debug看看源码哈,这个类:
org.apache.ibatis.ognl.OgnlOps
关键方法是这个:
public static int compareWithConversion(Object v1, Object v2) {
label75: {
int result;
if (v1 == v2) {
result = 0;
} else {
int t1 = getNumericType(v1);
int t2 = getNumericType(v2);
int type = getNumericType(t1, t2, true);
switch (type) {
case 6:
result = bigIntValue(v1).compareTo(bigIntValue(v2));
break;
case 7:
case 8:
break label75;
case 9:
result = bigDecValue(v1).compareTo(bigDecValue(v2));
break;
case 10:
if (t1 != 10 || t2 != 10) {
break label75;
}
if (v1 instanceof Comparable && v1.getClass().isAssignableFrom(v2.getClass())) {
result = ((Comparable)v1).compareTo(v2);
break;
}
if (!(v1 instanceof Enum) || !(v2 instanceof Enum) || v1.getClass() != v2.getClass() && ((Enum)v1).getDeclaringClass() != ((Enum)v2).getDeclaringClass()) {
throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
}
result = ((Enum)v1).compareTo(v2);
break;
default:
long lv1 = longValue(v1);
long lv2 = longValue(v2);
return lv1 == lv2 ? 0 : (lv1 < lv2 ? -1 : 1);
}
}
return result;
}
double dv1 = doubleValue(v1);
double dv2 = doubleValue(v2);
return dv1 == dv2 ? 0 : (dv1 < dv2 ? -1 : 1);
}