Mybatis的「if」 标签有坑之参数是0的时候会被过滤掉! |
您所在的位置:网站首页 › x为无法识别的参数 › Mybatis的「if」 标签有坑之参数是0的时候会被过滤掉! |
前言:
米娜,今天的文章还是简确用的文章,希望可以帮到你们。 Mybatis 有一些标签,用来支持动态 sql 语句,简单来说,这些标签可以控制 sql 语句的输出,设置某些条件来让Mapper输出不同的 sql 语句,今天这篇文章主要说一下使用标签会遇到的坑。 正文:一、复现问题 1.数据库的数据 2.Controller层代码 @RestController @RequestMapping("/study") public class StudentController { @Autowired StudentService studentService; @RequestMapping(value = "/selectStudent", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") public String selectStudent(Integer sex){ JSONObject result = new JSONObject(); List students = studentService.selectStudent(sex); result.put("data",students); return result.toString(); } }3.Dao层代码 public interface StudentMapper extends BaseMapper { List selectBySex(@Param("sex") Integer sex); }4.xml文件的代码 select * from student where 1=1 and sex = #{sex}5.postman请求的参数 根据上面的代码和数据库已有的数据,我们猜测sex传1的时候,应该有一条数据,sex传0的时候有两条数据,不传的时候有三条数据。我们现在看下结果: sex=1 ,和我们猜想的一样,1条数据 sex=0 ,出现了三条数据和我们的猜想不一样,问题复现出来了,这时候出现三条数据,说明标签没有起作用 sex传null的时候,和我们猜想的一样,3条数据 二、分析问题 1.我们先看下控制台打印sql的区别 sex=1 select * from student where 1=1 and sex = ? sex=null select * from student where 1=1 sex=0 select * from student where 1=1 可以明显看出来参数传0的时候,没有走标签里的条件,test判断的似乎把等于0的情况,也当做false,所以没有走if里面的部分。 and sex = #{sex}2.那为什么会造成sex=0 返回的是false,这得稍微看下MyBatis中一些关于动态SQL的接口和类,先看一张类图 我们可以看到关于if的标签设计到的类是IfSqlNode,那我们就先看下这个类 public class IfSqlNode implements SqlNode { private final ExpressionEvaluator evaluator; private final String test; private final SqlNode contents; public IfSqlNode(SqlNode contents, String test) { this.test = test; this.contents = contents; this.evaluator = new ExpressionEvaluator(); } public boolean apply(DynamicContext context) { if (this.evaluator.evaluateBoolean(this.test, context.getBindings())) { this.contents.apply(context); return true; } else { return false; } } }我们发现IfSqlNode的apply方法这里进行了判断,于是推测是否在这里进行条件的判断,我们再进一步看下evaluateBoolean方法 public boolean evaluateBoolean(String expression, Object parameterObject) { Object value = OgnlCache.getValue(expression, parameterObject); if (value instanceof Boolean) { return (Boolean)value; } else if (value instanceof Number) { return (new BigDecimal(String.valueOf(value))).compareTo(BigDecimal.ZERO) != 0; } else { return value != null; } }通过断点发现value的时候就是false啦,所以看下getValue方法 然后在不断往下追溯源码后,找到方法compareWithConversion,通过断点我们可以到,0和“”最终都会转化成0.0,所以在mybatis的if标签里0其实等价于“”,这也是为什么mybati中if test 0!=""判定为false的原因。 三、解决问题 1.在建表的时候如果某个字段定义成int类型,建议可以用1为基础往上加,这样就可以避免使用0来当参数筛选条件了,从根源上制止。 举个例子,sex可以用1表示男 2表示女 3表示未知 2.如果任性就是想用0来表示,可以在标签这样写 or sex==0 select * from student where 1=1 and sex = #{sex}然后点击postman测试一下,数据变成两条了 再看下打印的日志: => Preparing: select * from student where 1=1 and sex = ? ==> Parameters: 0(Integer) |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |