皮皮网
皮皮网
echarts有源码吗

【apollo源码分析(七)】【exe源码提取方法】【php git源码分享】mybatis ognl 源码

时间:2024-12-29 00:43:00 分类:时尚 编辑:网站授权源码PHP
1.小计01:MyBatis的OGNL
2.MyBatis动态SQL标签的用法
3.很开心,在使用mybatis的过程中我踩到一个坑。
4.mybatis if else if 条件判断SQL片段表达式取值和拼接
5.Mybatis OGNL导致的并发安全问题
6.为何Mybatis将Integer为0的属性解析成空串?

mybatis ognl 源码

小计01:MyBatis的OGNL

       作为程序员而言,一种理想的状态是我想到什么时候而且想写的时候就在写,不受地域和时间的限制,其实和作家写文章没有什么分别,apollo源码分析(七)不想写的时候就不用写。

       有些人可能不知道MyBatis中使用了OGNL,有些人知道用到了OGNL却不知道在MyBatis中如何使用,本文就是讲如何在MyBatis中使用OGNL。

       如果我们搜索OGNL相关的内容,通常的结果都是和Struts有关的,你肯定搜不到和MyBatis有关的,虽然和Struts中的用法类似但是换种方式理解起来就有难度。

MyBatis常用OGNL表达式

       e1 or e2

       e1 and e2

       e1 == e2,e1 eq e2

       e1 != e2,e1 neq e2

       e1 lt e2:小于

       e1 lte e2:小于等于,其他gt(大于),gte(大于等于)

       e1 in e2

       e1 not in e2

       e1 + e2,e1 * e2,e1/e2,e1 - e2,e1%e2

       !e,not e:非,求反

       e.method(args)调用对象方法

       e.property对象属性值

       e1[ e2 ]按索引取值,List,数组和Map

       @class@method(args)调用类的静态方法

       @class@field调用类的静态字段值

       上述内容只是合适在MyBatis中使用的OGNL表达式,完整的表达式点击这里。

MyBatis中什么地方可以使用OGNL?

       如果你看过深入了解MyBatis参数,也许会有印象,因为这篇博客中提到了OGNL和一些特殊用法。

       如果没看过,建议找时间看看,上面这篇博客不是很容易理解,但是理解后会很有用。

       MyBatis中可以使用OGNL的地方有两处:

       动态SQL表达式中

       ${ param}参数中

       上面这两处地方在MyBatis中处理的时候都是使用OGNL处理的。

       (1)动态SQL表达式中

       test的值会使用OGNL计算结果

<select id="xxx" ...>select id,name,... from country<where><if test="name != null and name != ''">name like concat('%', #{ name}, '%')</if></where></select>

       <bind>的value值会使用OGNL计算

<select id="xxx" ...>select id,name,... from country<bind name="nameLike" value="'%' + name + '%'"/><where><if test="name != null and name != ''">name like #{ nameLike}</if></where></select>

       注意:对<bind参数的调用可以通过#{ }或 ${ } 方式获取,#{ }可以防止注入。

       在通用Mapper中支持一种UUID的主键,在通用Mapper中的实现就是使用了<bind>标签,这个标签调用了一个静态方法,exe源码提取方法大概方法如下:

<bind name="username_bind" value='@java.util.UUID@randomUUID().toString().replace("-", "")' />

       这种方式虽然能自动调用静态方法,但是没法回写对应的属性值,因此使用时需要注意。

       (2)${ param}参数中

<select id="xxx" ...>select id,name,... from country<where><if test="name != null and name != ''">name like '${ '%' + name + '%'}'</if></where></select>

       ${ '%' + name + '%'},而不是而不是%${ name}%,这两种方式的结果一样,但是处理过程不一样

       在MyBatis中处理${ }的时候,只是使用OGNL计算这个结果值,然后替换SQL中对应的${ xxx},OGNL处理的只是${ 这里的表达式}。 这里表达式可以是OGNL支持的所有表达式,可以写的很复杂,可以调用静态方法返回值,也可以调用静态的属性值。

使用OGNL实现单表的分表功能

       上面说的是OGNL简单的使用方法。这里举个OGNL实现数据库分表的例子。

       分表这个功能是通用Mapper中的新功能,允许在运行的时候指定一个表名,通过指定的表名对表进行操作。这个功能实现就是使用了OGNL。

       首先并不是所有的表都需要该功能,因此定义了一个接口,当参数(接口方法只有实体类一个参数)对象继承该接口的时候,就允许使用动态表名。

public interface IDynamicTableName { /** * 获取动态表名 - 只要有返回值,不是null和'',就会用返回值作为表名 * * @return */String getDynamicTableName();}<if test="@tk.mybatis.mapper.util.OGNL@isDynamicParameter(_parameter) and dynamicTableName != null and dynamicTableName != ''">${ dynamicTableName}</if><if test="@tk.mybatis.mapper.util.OGNL@isNotDynamicParameter(_parameter) or dynamicTableName == null or dynamicTableName == ''">defaultTableName</if>

       由于我需要判断_parameter是否继承了IDynamicTableName接口,简单的写法已经无法实现,所以使用了静态方法,这两个方法如下:

/** * 判断参数是否支持动态表名 * * @param parameter * @return true支持,false不支持 */public static boolean isDynamicParameter(Object parameter) { if (parameter != null && parameter instanceof IDynamicTableName) { return true;}return false;}/** * 判断参数是否不支持动态表名 * * @param parameter * @return true不支持,false支持 */public static boolean isNotDynamicParameter(Object parameter) { return !isDynamicParameter(parameter);}

       根据<if>判断的php git源码分享结果来选择使用那个表名。

       另外注意XML判断中有一个dynamicTableName,这个参数是根据getDynamicTableName方法得到的,MyBatis使用属性对应的getter方法来获取值,不是根据field来获取值。

原文:/post/

MyBatis动态SQL标签的用法

       在 MyBatis 中,动态 SQL 为开发者提供了一种灵活的方式来构建 SQL 语句,以适应不同场景的需要。动态 SQL 主要通过 OGNL 表达式实现,简化了在 SQL 语句中进行逻辑判断的过程。

       实现动态 SQL 的关键元素有 if、choose、where、set 和 foreach 等。它们的用法与 JSP 中的 JSTL 语法类似,接下来分别介绍这些元素的主要功能。

       动态 SQL 中的 if 语句允许开发者在 SQL 语句中添加条件判断,使得 SQL 语句的构建更加灵活。

       choose 语句则为 SQL 条件提供了多选项的逻辑,使得条件判断更加丰富。

       where 语句在动态 SQL 中主要用于简化 SQL 语句中 where 子句中的条件判断,帮助开发者方便地添加和管理条件。

       注意:在使用 where 元素时,如果输出后的条件字符串以 "and" 开头,MyBatis 会自动忽略第一个 "and";对于以 "or" 开头的情况同样处理。在 where 元素内部,无需担心空格问题,MyBatis 会自动处理。

       set 元素主要应用于更新操作,其功能与 where 元素相似,用于动态添加更新条件。

       foreach 语句则提供了遍历列表元素的趋势黑马图源码功能,适用于在 SQL 语句中进行多条件操作。

       动态 SQL 中 trim 元素具备在自身内容前添加前缀、后添加后缀的功能,通过 prefix、suffix、prefixOverrides 和 suffixOverrides 属性控制,有助于实现更加灵活的 SQL 语句构建。

       在实际的 Java 代码开发中,通过结合 MyBatis 的动态 SQL 语句,开发者可以构建出高度灵活且适应性强的 SQL 语句,有效提升开发效率和代码可维护性。

很开心,在使用mybatis的过程中我踩到一个坑。

       在实际开发过程中,我遇到了mybatis的一个问题,觉得很有必要记录下来并分享给大家。

       这个坑的具体情况是这样的:在mybatis中,OgnlOps.equal(0,"")返回的是true,这违背了我们的常识,并且会带来一些问题。

       接下来,我将按照遇到问题 -> 分析问题 -> 解决问题的思路,用追踪源码的方法,对这个问题进行剖析。

       同时,我会分享一下我是如何通过逆向排查的方法,通过Debug模式找到关键源码,并解决这个问题的。

       本文源码:mybatis 3.5.3版本。

       背景介绍和需求分析

       为了简化问题,我们假设有一个订单表,翡翠拍卖源码查询表结构如下:

       为了方便说明,我们假设表里面只有两条数据:订单号为的订单状态为0(关闭),订单号为的订单状态为1(开启)。

       已经开发好的功能是模糊查询订单名称,接口如下:

       现在需要在已有功能上添加一个根据状态过滤订单的功能。

       假设某个页面有这样的一个下拉框,可以根据订单状态过滤订单数据。

       准备开发

       现在明确了需求,根据订单状态进行过滤。

       很简单,最主要的修改地方就是对mapper.xml的修改。

       开始自测,遇到问题

       为了确保功能的正确性,我进行了单元测试,分别传入状态0和1,预期的结果是各自查询出一条数据。

       然而,执行结果却与预期不符,status=0时查询出2条数据,status=1时查询出1条数据。

       当时我意识到这个问题可能并不简单,于是决定分析原因。

       分析问题

       为了找到问题的根源,我首先将sql打印出来,查看最终执行的sql。

       通过分析sql,我发现当status为0时,mybatis并没有给我们拼接where关键字。

       逆向排查法

       为了定位问题,我通过日志找到了关键源码,并使用逆向排查的方法进行追踪。

       最终,我发现问题的根源在于mybatis中的OgnlOps.equal(0,"")返回了true。

       关键源码

       通过分析源码,我找到了导致这个问题的关键代码,并解决了这个问题。

       解决问题

       为了解决这个问题,我修改了mapper.xml文件中的if标签,最终实现了预期效果。

       总结

       这次的经历让我深刻认识到,在开发过程中遇到问题时,要善于分析、思考和总结,才能不断提升自己的技能。

mybatis if else if 条件判断SQL片段表达式取值和拼接

       在进行项目开发时,遇到复杂条件的动态查询是常有的事。虽然 MyBatis 不直接支持 if elseif 的判断逻辑,但可通过 choose when otherwise结构间接实现。这种结构类似于 if-else-if 条件判断,如果 choose 标签中的 when 条件不成立,则执行 otherwise 中的内容。

       在先前的开发中,使用 if 标签进行条件判断,条件之间并列存在。而如今,引入 choose when otherwise 结构,仅需一个条件成立,其他条件便不再判断,若没有成立的条件,则执行 otherwise 标签中的内容。下面是一个真实的例子,旨在帮助理解这一用法,可作为参考。

       例如,在筛选查询用户信息时,通过条件标签 choose when otherwise实现了 if-else-if 判断功能。choose 标签中,当条件一不成立时,会执行 otherwise 中定义的 SQL 条件。具体实现及详细使用方法,可参考相关文章了解更多。

       在编写 SQL 语句时,常常会遇到一些重复的 SQL 语句片段,为避免重复编写,可以使用 SQL 片段方法。MyBatis 提供了 元素,用于定义 SQL 片段。每个片段都有唯一的 id,用于在其他地方引用。在 元素中,可以使用 、、、等标签定义复杂的 SQL 语句。下面是一个简单的示例,展示了如何定义和引用 SQL 片段。

       定义 SQL 片段后,可以使用 元素引入,并在需要的地方使用。例如,查询用户信息时,可以通过片段定义 SELECT 和 WHERE 语句部分,实现代码的复用和维护。

       在传递参数时,使用 #{ params} 方式获取参数值,其中的 #{ xx} 实际上是 OGNL(Object-Graph Navigation Language)表达式。MyBatis 解析 XML 映射文件时,会将 #{ xx} 转换成预处理语句参数,由 JDBC 生成 "? 符号",并在底层设置参数。

       OGNL 是一种对象-图行导航语言,用于对象和视图之间的数据交互,能够访问对象属性并调用方法。MyBatis 使用 OGNL 表达式进行参数处理,生成带占位符的 SQL 语句,并设置参数。完整的 OGNL 表达式文档可以在线查看。

       MyBatis 中使用 OGNL 的场景包括:

       MySQL 类型的 like 查询

       通用 like 查询

       例如,查询时使用 OGNL 计算条件值,可以灵活处理字符串的前后缀匹配。

       在通用 Mapper 中,对于 UUID 主键的处理通过 元素调用静态方法实现,这种方式可以自动调用静态方法,但需要注意属性值的回写。在 like 查询中,使用正确的 OGNL 表达式 ${ '%' + name + '%'} 可确保查询结果的正确性。

       处理 ${ } 表达式时,MyBatis 使用 OGNL 计算表达式的值,然后替换 SQL 中对应的 ${ xxx}。这允许在表达式中使用 OGNL 支持的所有功能,包括调用静态方法和属性值。

       例如,判断入参属性值是否包含子字符串,可以使用 contains方法进行判断,以确保查询语句的正确性和效率。

Mybatis OGNL导致的并发安全问题

       Mybatis是一个轻量级半自动化ORM框架,通过xml描述符或注解将对象与SQL语句结合,实现面向对象与数据库映射的简化。其最大优势在于将应用程序与Sql语句解耦,Sql语句在xml文件中定义。

       OGNL(Object-Graph Navigation Language)是Mybatis中广泛使用的表达式语言,用于设置和获取Java对象属性,执行列表投影和lambda表达式。灵活的OGNL表达式在Struts2等框架中应用时,也会引入可执行漏洞风险。

       某公司使用Mybatis 3.2.3版本作为数据访问层。在线业务系统运行期间,出现并发安全问题。异常表现为随机出现,构造特定OGNL表达式时不会重现,具体异常堆栈信息显示List的size()方法不可访问。此问题在测试环境未重现,占总调用次数的0.%。

       编写模拟多线程并发环境下的测试代码以验证问题。并发测试代码执行后,异常在预期的并发环境下重现。异常堆栈信息指向OgnlRuntime类无法访问java.util.Collections私有成员SingletonList。

       问题关键在于method作为共享变量,即java.util.Collections$SingletonList.size()方法。在第一个线程允许调用method方法,第二个线程将其设为不可访问后,第一个线程再次调用时引发MethodFailedException异常。这是典型的并发同步问题。

       OGNL 2.7版本已修复此问题,Mybatis在3.3.0版本中进行了修复升级。源码已直接嵌入mybatis包中,解决了并发访问共享资源导致的异常问题。

为何Mybatis将Integer为0的属性解析成空串?

       在一次代码审查中,同事分享了一个有趣的问题:在Mybatis中,Integer类型的age为0时,为什么会解析成空串,导致SQL语句的条件判断失效?

       为了解答疑问,作者查阅了Mybatis的源码。首先,从GitHub上的最新版本下载代码,构建测试用例。在SqlSessionFactoryBuilder的构建流程中,经过XMLConfigBuilder解析配置,构建Configuration类,进而生成SqlSessionFactory和SqlSession。执行过程中,mybatis使用SimpleExecutor或CachingExecutor,后者涉及动态代理和拦截器的执行,关键在于DynamicSqlSource和IfSqlNode类。

       在IfSqlNode的evaluator.evaluateBoolean方法中,使用了OGNLCache来获取值,而问题出在OGNL表达式对空字符串的处理上。在ASTNotEq类的compareWithConversion方法中,当字符串长度为0时,会被解析为0.0,这不仅影响Integer,也影响Float和Double类型。因此,问题的根源在于OGNL表达式对空字符串的解析规则。

本文地址:http://abssuliao.net/html/50d427295677.html

copyright © 2016 powered by 皮皮网   sitemap