mybatis开发,你用 xml 还是注解?我 pick ... (2)

简介: mybatis开发,你用 xml 还是注解?我 pick ... (2)

我第一次看到这个地方的时候,一下才恍然大悟过来,我才明白,@Select 的本质还是 xml 文件的形式啊。只是换了个展现形式而已。


我之前的一个问题,或者说是错误的看法也就迎刃而解了。


我之前认为 @Select 的方式是只能支持简单 SQL 的书写,对于一些类似于判空的需求是不支持的。(因为对 mybatis 注解开发确实不熟)


比如在 xml 文件中这样去写:


<when test='startPage !=null and pageSize != null '>
  LIMIT #{startPage},#{pageSize}
</when>


只是这个写法,呃,怎么说呢,非常不优雅。


不要为了注解而注解,很明显,这种情况直接用 xml 形式更好。


到这里,我们也知道了,基于 @Select 注解的方式开发时, mybatis 会通过反射获取到注解里面的 SQL ,而这些 SQL 需要一些比较复杂功能,比如判断条件是否为空时,可以用 script 标签包裹起来。写法和在 xml 里面开发是一样的。


接下来,我们看看 @SelectProvider 方法是什么个样式。


还是在同样的方法中,只是走向了另外一个分支:


此时的 sqlProviderAnnotation 里面的东西如下:


接着去 new ProviderSqlSource 对象:


在这个方法中,获取到了注解上的具体的提供 SQL 原始语句的方法。


注意红框中框起来的 providerMethod 对象,后面获取真正执行的 SQL 语句的时候还会用到。


同时,我们可以看到 ProviderSqlSource 是 SqlSource 的实现类。


所以,不管是 xml 还是注解,最终都需要获取到一个 SqlSource 对象。


而在本文的示例代码中, xml 和 @Select 生成的是 RawSqlSource。


@SelectProvider 生成的是 ProviderSqlSource。他们里面放的东西是不一样的。


在 RawSqlSource 里面的 sqlSource 变量(类型 StaticSqlSource)放的已经是从 xml 或者 @Select 注解中获取到的 SQL 原始语句了(但是里面的变量还没替换,因为程序启动过程中根本不知道变量的值具体是什么,如果有一些条件表达式的话同理)。


而在ProviderSqlSource 里面,我们前面已经说了,放的是 @SelectProvider 注解上具体的提供 SQL 语句的方法,仅仅是方法,而不是语句。


前面的所有分析都是在我们的方法真正执行之前,接下来,才会 debug 到我们的测试用例,因为只有我们的测试用例里面才有真正的入参, mybatis 才能根据入参,执行最终的 SQL 语句。


所以,接下来,我们就是要找到真正生成 SQL 语句的地方,这里就能和之前文章《很开心,在使用mybatis的过程中我踩到一个坑》中的逆向排查法中得出的结论进行呼应了。


进入 getBoundSql 我们可以看到第292行,就是通过 sqlSource 的 getBoundSql 方法获取到的 boundSql 对象:


org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql


这不就又呼应上了吗?又看到 sqlSource 了。


所以,接下来,我们看一下这两个方法就可以了:


org.apache.ibatis.builder.StaticSqlSource#getBoundSql
org.apache.ibatis.builder.annotation.ProviderSqlSource#getBoundSql


首先看一下 StaticSqlSource 的实现:


里面的一些关键参数如下:


首先可以 sql 变量,里面是一条待加工的 SQL 语句,我们前面已经分析过了,程序启动的过程中,这里为什么不替换呢?


因为不知道换成啥呀。


那你觉得在这个地方会替换吗?


还是不会的。虽然我们已经告诉 mybatis , userName 就是 why 了,但如果在这个地方把 why 带到 SQL 里面去,我们倒是可以获得一个完整的正确的 SQL。


但是,如果我们传入的是 “why or 1=1”呢?


这是什么东西我相信你一下就恍然大悟了吧,SQL 注入呀。


另外插一句,如果想看 SQL 注入的情况,就是走到 DynamicSqlSource 的情况,在 xml 中把 # 换成 $ 就行,有兴趣的可以试一试。


我这里只是给你截个图,瞅一眼:


好了,我们接着刚才继续说。


继续 debug 会走到这方法中去:


org.apache.ibatis.executor.SimpleExecutor#doQuery


而这个方法的第 62 行,prepareStatement,这个东西不用说了吧,从学 JDBC 的时候就用上它了,老朋友了:


最后去执行真正的查询操作,处理返回值。

接着看 ProviderSqlSource 的实现,注意看我圈起来的那部分的分支判断:


无非就是判断有几个参数,反射方法调用的时候需要怎么传参而已。最终会调用到这个方法里面来获取 SQL 语句:


可以看一下这个时候 providerMethod 和 sql 变量分别是什么:


而这里这个 providerMethod 怎么来的知道了吧?我们前面刚刚分析过了。


new ProviderSqlSource 对象的时候,我还专门说了:“注意红框中框起来的 providerMethod 对象,后面获取真正执行的 SQL 语句的时候还会用到。”

就是在这个地方用到的。


你看,又呼应上了。


这个时候,我们获取到了原始的 SQL 语句了,也有参数了,这样的场景和我们刚刚分析的情况就一模一样了,所以后面的逻辑都一样,进行了代码复用:


进入第 98 行,也就是下面这个我们之前分析过的方法:


org.apache.ibatis.builder.SqlSourceBuilder#parse

在这个方法中,返回了一个 StaticSqlSource 对象:


再次呼应,流程是一样一样的。


另外,再说一下,用 @SelectProvider 注解时的 class 对象里面的方法还可以这样去写,有兴趣的可以去研究一下:


好了,我们的论证部分就算是完了,我发现这个东西,用视频真的几分钟就讲清楚了,描述起来还是有点困难的,难道是在逼我当UP主吗?


不知道大家看的是否明白了,如果对 mybatis 了解不多的朋友可能看起来有一点吃力,但是没有关系,你就把这篇文章当做一个导读,然后自己搞个 Demo 跑起来,玩一玩就行。

目录
相关文章
|
15天前
|
SQL Java 数据库连接
MyBatis-Plus高级用法:最优化持久层开发
MyBatis-Plus 通过简化常见的持久层开发任务,提高了开发效率和代码的可维护性。通过合理使用条件构造器、分页插件、逻辑删除和代码生成器等高级功能,可以进一步优化持久层开发,提升系统性能和稳定性。掌握这些高级用法和最佳实践,有助于开发者构建高效、稳定和可扩展的企业级应用。
43 13
|
2月前
|
SQL Java 数据库连接
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。本文讲解了最新版MP的使用教程,包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段等核心功能。
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
|
2月前
|
SQL 缓存 Java
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
91 5
|
2月前
|
Java 数据库连接 mybatis
Mybatis使用注解方式实现批量更新、批量新增
Mybatis使用注解方式实现批量更新、批量新增
62 3
|
2月前
|
SQL 存储 数据库
深入理解@TableField注解的使用-MybatisPlus教程
`@TableField`注解在MyBatis-Plus中是一个非常灵活和强大的工具,能够帮助开发者精细控制实体类与数据库表字段之间的映射关系。通过合理使用 `@TableField`注解,可以实现字段名称映射、自动填充、条件查询以及自定义类型处理等高级功能。这些功能在实际开发中,可以显著提高代码的可读性和维护性。如果需要进一步优化和管理你的MyBatis-Plus应用程
209 3
|
2月前
|
Java 数据库连接 mybatis
Mybatis使用注解方式实现批量更新、批量新增
Mybatis使用注解方式实现批量更新、批量新增
178 1
|
4月前
|
SQL XML Java
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
文章介绍了MyBatis的简单增删改查操作,包括创建数据表、实体类、配置文件、Mapper接口及其XML文件,并解释了`#{}`预编译参数和`@Param`注解的使用。同时,还涵盖了resultType与resultMap的区别,并提供了完整的代码实例和测试用例。
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
|
3月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
88 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
3月前
|
XML Java 数据格式
手动开发-简单的Spring基于XML配置的程序--源码解析
手动开发-简单的Spring基于XML配置的程序--源码解析
92 0
|
4月前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit