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 ...
随机推荐
- zen coding一个牛的不行的html和css开发工具
zen coding 是一种仿css选择器的语法来快速开发html和css的开源项目.现已更名为Emmet.可以到github上下载拜读.在这个都想偷懒的世界里,此方法可以极大的缩短开发人员的开发时间 ...
- php的文件引用
最近研究公司代码时发现了set_include_path(dirname(__FILE__));这样一行代码,在网上查了些资料,才把这个方法的作用弄清楚. 首先,dirname(__FILE__)这个 ...
- int类型和byte类型的强制类型转换
今天在读<Java网络编程>这本书的第二章 流 时,看到书中有一个地方关于int强制转换为byte类型时应注意的地方.这个地方有点细节,不过就应该把这种细节把握住. 情况是这样的,讲到In ...
- Java实现的高效计数器
本文转载地址: http://blog.csdn.net/snarlfuture/article/details/17049731 在统计来自数据库或文本中某些内容的频率时,你可 ...
- Linux服务器的远程IP限制
系统环境: Linux-centOS+ubuntu 操作: 编辑允许通过IP 路径:vim /etc/hosts.allow sshd:192.168.1.1 编辑禁止通过IP 路径:vim /etc ...
- SmartCoder每日站立会议10
站立会议内容: 准备为上交第一阶段项目进行加班,将各个页面联系起来,静态地图变为动态转换,考虑地图全屏或者是小屏即消息展示方式 1.站立会议照片: 2.任务展板: 3.燃尽图:
- OpenStack命令 创建网络和路由管理
1.登陆用户 :tdy(前提条件创建了tdy用户) 编写登陆用户tdy用户 脚本文件 user-operc.sh user-operc.sh : 登陆用户tdy: $ source user-ope ...
- ES6核心内容精讲--快速实践ES6(三)
Promise 是什么 Promise是异步编程的一种解决方案.Promise对象表示了异步操作的最终状态(完成或失败)和返回的结果. 其实我们在jQuery的ajax中已经见识了部分Promise的 ...
- 2016计蒜之道复赛B题:联想专卖店促销
题解 思路: 二分答案,设我们要check的值为x. 注意到每一个礼包都有,一个U盘,一个鼠标. 剩余的,分别为一个机械键盘,一个U盘,一个鼠标. 当礼包数目为x时,我们至多可以提供a-x个普通,b- ...
- scroll抖动问题
参考软文: http://www.cnblogs.com/coco1s/p/5499469.html function throttle(func, wait, mustRun) { var time ...