mybatis if test加筛选条件
最近在项目使用mybatis中碰到个问题
- <if test="type=='y'">
- and status = 0
- </if>
当传入的type的值为y的时候,if判断内的sql也不会执行,抱着这个疑问就去看了mybatis是怎么解析sql的。下面我们一起来看一下mybatis 的执行过程。
DefaultSqlSession.class 121行
- public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
- try {
- MappedStatement ms = configuration.getMappedStatement(statement);
- executor.query(ms, wrapCollection(parameter), rowBounds, handler);
- } catch (Exception e) {
- throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
- } finally {
- ErrorContext.instance().reset();
- }
- }
在 executor.query(ms, wrapCollection(parameter), rowBounds, handler);
执行到BaseExecutor.class执行器中的query方法
- public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
- BoundSql boundSql = ms.getBoundSql(parameter);
- CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
- return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
- }
在query的方法中看到boundSql,是通过 ms.getBoundSql(parameter);获取的。
再点进去可以看到MappedStatement.class类中的getBoundSql方法
- public BoundSql getBoundSql(Object parameterObject) {
- BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
- List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
- if (parameterMappings == null || parameterMappings.size() <= 0) {
- boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
- }
- // check for nested result maps in parameter mappings (issue #30)
- for (ParameterMapping pm : boundSql.getParameterMappings()) {
- String rmId = pm.getResultMapId();
- if (rmId != null) {
- ResultMap rm = configuration.getResultMap(rmId);
- if (rm != null) {
- hasNestedResultMaps |= rm.hasNestedResultMaps();
- }
- }
- }
- return boundSql;
- }
看到其中有sqlSource.getBoundSql(parameterObject); sqlsource是一个接口。
- /**
- *
- * This bean represets the content of a mapped statement read from an XML file
- * or an annotation. It creates the SQL that will be passed to the database out
- * of the input parameter received from the user.
- *
- */
- public interface SqlSource {
- BoundSql getBoundSql(Object parameterObject);
- }
类中getBoundSql是一个核心方法,mybatis 也是通过这个方法来为我们构建sql。BoundSql 对象其中保存了经过参数解析,以及判断解析完成sql语句。比如<if> <choose> <when> 都回在这一层完成,具体的完成方法往下看,那最常用sqlSource的实现类是DynamicSqlSource.class
- public class DynamicSqlSource implements SqlSource {
- private Configuration configuration;
- private SqlNode rootSqlNode;
- public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
- this.configuration = configuration;
- this.rootSqlNode = rootSqlNode;
- }
- public BoundSql getBoundSql(Object parameterObject) {
- DynamicContext context = new DynamicContext(configuration, parameterObject);
- rootSqlNode.apply(context);
- SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
- Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
- SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
- BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
- for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
- boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
- }
- return boundSql;
- }
- }
核心方法是调用了rootSqlNode.apply(context); rootSqlNode是一个接口
- public interface SqlNode {
- boolean apply(DynamicContext context);
- }
可以看到类中 rootSqlNode.apply(context); 的方法执行就是一个递归的调用,通过不同的
实现类执行不同的标签,每一次appll是完成了我们<></>一次标签中的sql创建,计算出标签中的那一段sql,mybatis通过不停的递归调用,来为我们完成了整个sql的拼接。那我们主要来看IF的实现类IfSqlNode.class
- public class IfSqlNode implements SqlNode {
- private ExpressionEvaluator evaluator;
- private String test;
- private SqlNode contents;
- public IfSqlNode(SqlNode contents, String test) {
- this.test = test;
- this.contents = contents;
- this.evaluator = new ExpressionEvaluator();
- }
- public boolean apply(DynamicContext context) {
- if (evaluator.evaluateBoolean(test, context.getBindings())) {
- contents.apply(context);
- return true;
- }
- return false;
- }
- }
可以看到IF的实现中,执行了 if (evaluator.evaluateBoolean(test, context.getBindings())) 如果返回是false的话直接返回,否则继续递归解析IF标签以下的标签,并且返回true。那继续来看 evaluator.evaluateBoolean 的方法
- public class ExpressionEvaluator {
- public boolean evaluateBoolean(String expression, Object parameterObject) {
- Object value = OgnlCache.getValue(expression, parameterObject);
- if (value instanceof Boolean) return (Boolean) value;
- if (value instanceof Number) return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);
- return value != null;
- }
关键点就在于这里,在OgnlCache.getValue中调用了Ognl.getValue,看到这里恍然大悟,mybatis是使用的OGNL表达式来进行解析的,在OGNL的表达式中,'y'会被解析成字符,因为java是强类型的,char 和 一个string 会导致不等。所以if标签中的sql不会被解析。具体的请参照 OGNL 表达式的语法。到这里,上面的问题终于解决了,只需要把代码修改成:
- <if test='type=="y"'>
- and status = 0
- </if>
就可以执行了,这样"y"解析出来是一个字符串,两者相等!
mybatis if test加筛选条件的更多相关文章
- jqgrid 表格中筛选条件的多选下拉,树形下拉 ;文本框清除插件;高级查询多条件动态筛选插件[自主开发]
/** * @@desc 文本框清除按钮,如果isAutoWrap为false当前文本框父级必须是relative定位,boostrap参考input-group * @@author Bear.Ti ...
- Mybatis中动态SQL多条件查询
Mybatis中动态SQL多条件查询 mybatis中用于实现动态SQL的元素有: if:用if实现条件的选择,用于定义where的字句的条件. choose(when otherwise)相当于Ja ...
- MySql 筛选条件、聚合分组、连接查询
筛选条件 比较运算符 等于: = ( 注意!不是 == ) 不等于: != 或 <> 大于: > 大于等于: >= 小于: < 小于等于: <= IS NULL I ...
- element ui table表头动态筛选条件
本文主要实现:根据el-table表格数据自动生成表头筛选条件的方法,可根据表格数据动态调整. el-table表格的表头增加筛选功能,大家平时都是怎么实现的呢?先看看官方文档的例子: 1 <t ...
- sql之表连接 筛选条件放在 连接外和放在连接里的区别
使用一个简单的例子,说明他们之间的区别 使用的表:[Sales.Orders]订单表和[Sales.Customers]客户表,和上一篇博客的表相同 业务要求:查询出 : 所有的用户 在 2012-1 ...
- 关于 Mybatis 设置懒加载无效的问题
看了 mybatis 的教程,讲到关于mybatis 的懒加载的设置: 只需要在 mybatis 的配置文件中设置两个属性就可以了: <settings> <!-- 打开延迟加载的开 ...
- MySQL 误删数据、误更新数据(update,delete忘加where条件)
MySQL 误操作后数据恢复(update,delete忘加where条件) 关键词:mysql误删数据,mysql误更新数据 转自:https://www.cnblogs.com/gomysql/p ...
- vue的data的数据进行指定赋值,用于筛选条件的清空,或者管理系统添加成功后给部分数据赋值为空
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- MySQL 误操作后数据恢复(update,delete忘加where条件)
在数据库日常维护中,开发人员是最让人头痛的,很多时候都会由于SQL语句写的有问题导致服务器出问题,导致资源耗尽.最危险的操作就是在做DML操作的时候忘加where条件,导致全表更新,这是作为运维或者D ...
随机推荐
- php中表单提交复选框与下拉列表项
在赶项目中,抽出半个小时来写篇博客吧,这个功能说实话不难,为什么要写呢,因为在复选框那里有小小的难点,我试了好多遍才试成功的,希望能为以后需要帮助的同学提供点思路. 先看一下我做的效果吧 就是给每个业 ...
- Python日期时间的相关操作
1.获取当前时间戳 import time t=time.time() print t 1459994552.51 #以秒为单位的 2.格式化日期 time.localtime() 返回当前时间的: ...
- O(mn)实现LCIS
序: LCIS即求两序列的最长公共不下降子序列.思路于LCS基本一致. 用dp[i][j]记录当前最大值. 代码实现: /* About: LCIS O(mn) Auther: kongse_qi D ...
- 使用 onpropertychange 和 oninput 检测 input、textarea输入改变
检测input.textarea输入改变事件有以下几种: 1.onkeyup/onkeydown 捕获用户键盘输入事件. 缺陷:复制粘贴时无法检测 2.onchenge 缺陷:要满足触发条件:当前对象 ...
- redis之sentinel概述
一.配置sentinel 修改的是这条: 对应: 上面那条配置需要注意:<master-name>:监控主节点的名称 <ip>:监控主节点的ip <redis-por ...
- git笔记--git@OSC
之前安装了git,用了不久就升级系统了,发现又忘记了步骤,虽然网上有很多教程,但寻找需要浪费太多的时间,由于github连接比较慢,所以使用了开源中国的托管http://git.oschina.net ...
- 如何让CSS区别IE版本
关于IE浏览器实在太坑爹了,但你又不得不去解决它,不过就本人所知,IE8—IE10差别不大,至少本人还没有遇到过在IE8环境下到了IE9及以上版本就出现坑爹的问题,但我们又不得不面对IE8以下的版本, ...
- 18个你可能不相信是用CSS制作出来的东西
与流行的看法相反,CSS不仅仅是用来提供一个WEB页面的基本风格,以使它看起来更有吸引力.还有很多其他的事情,CSS也可以做的很好.由于它创建动画和交互的能力,CSS集合HTML以及JavaScrip ...
- Java Maps
HashMap 是线程不安全的,主要对于写操作来说,两个以上线程同时写入Map会被互相覆盖.线程安全指的保证对同一个map的写入操作按照顺序进行,一次只能一个线程更改.比如向HashMap里put(k ...
- Advanced Sort Algorithms
1. Merge Sort public class Mergesort { private int[] numbers; private int[] helper; private int numb ...