Ⅰ 从源码角度分析 Mybatis 工作原理
本文以入门级示例说明 MyBatis 工作原理,涵盖数据库准备、添加 MyBatis、配置、Mapper、测试程序、生命周期、映射器、架构、SqlSession 机制等内容。通过源码解析详细展现 MyBatis 如何将 java 代码与数据库操作紧密结合。
数据库准备:针对用户表进行 CRUD 操作,设计数据模型。
添加 MyBatis:Maven 依赖配置,引入 MyBatis 依赖。
MyBatis 配置:XML 配置文件设置数据源、事务管理器。
Mapper:包含 Mapper.xml 和 Mapper.java 文件,实现 SQL 模板与 Java 对象绑定。
测试程序:MyBatisDemo.java 文件,展示如何使用 SqlSession 执行操作。
MyBatis 生命周期:SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession 的创建、使用与释放。
映射器:接口定义与动态代理生成,完成 SQL 与 Java 方法的映射。
架构:配置层、接口层、数据处理层、框架支撑层,展现 MyBatis 体系结构。
SqlSession 内部工作机制:解析 SQL、管理缓存、执行事务、处理结果集。
总结:MyBatis 通过封装、映射、执行等机制,简化了 Java 与数据库的交互过程,实现数据操作的便捷与高效。
Ⅱ Mybatis源码分析
上面这两幅图来源于网络,不过画的很好,基本说明了Mybatis的架构流程。
说明:
Executor
MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
StatementHandler
封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
ParameterHandler
负责对用户传递的参数转换成JDBC Statement 所需要的参数
ResultSetHandler
负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
TypeHandler
负责java数据类型和jdbc数据类型之间的映射和转换
SqlSource
负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回BoundSql表示动态生成的SQL语句以及相应的参数信息
基本上Mybatis的流程就是这样了,其中还有很多实现细节暂时看不太懂。 我认为学习框架源码分为两步:
目前第一步尚有问题,需要多走几遍源码,加深下理解,一起加油~~
Ⅲ Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节
这是 Mybatis 系列博客的第四篇,我将扩展一些其他特性或使用细节,掌握它们可以更优雅、高效地使用 mybatis。
本文的所有测试例子都是基于本系列 Mybatis 第一篇文章的项目,相关博客如下:
Mybatis源码详解系列(一)--持久层框架解决了什么及如何使用Mybatis
Mybatis源码详解系列(二)--Mybatis如何加载配置及初始化
Mybatis源码详解系列(三)--从Mapper接口开始看Mybatis的执行逻辑
在分析源码时,我们提到过 ResultHandler 这个接口。当 Mapper 接口的入参列表中包含 ResultHandler 且返回类型为 void 时,mybatis 会将映射完的每一个 Employee 对象传入 ResultHandler 中。通过 ResultHandler,我们可以对传进来的 Employee 对象进行任意处理。
这里我提供了一个 ResultHandler 实现类的示例。我认为,官方之所以提供 ResultHandler,是考虑到 resultMap 也有映射不了的对象而做的补充。所以,当我们遇到 resultMap 也映射不了的对象时,可以考虑使用 ResultHandler。
在使用篇中,我们使用 pagehelper 来支持分页功能,其实,mybatis 已经自带了分页功能。和 ResultHandler 一样,我们只需要改造下 Mapper 接口。通过 RowBounds 中指定好结果的范围,mybatis 就会帮我们自动分页。相比使用插件,这种方式不是更简单吗?那么,我为什么还要使用插件呢?其实,当我们看到控制台打印的 sql,就应该知道原因了。mybatis 使用 RowBounds 进行分页,本质上是把所有数据查出来,再放到应用内存里分页,这种方式非常耗性能和内存。所以,RowBounds 了解一下就可以了,实际项目中分页还是考虑引入插件吧。
在使用篇中,我们通过配置 lazyLoadingEnabled 来开启延迟加载。按理来说,只有我调用了 getDepartment 时,才会触发查询部门的操作,不调用的话永远都不会触发。而实际上真的是这样吗?下面的方法中,我们把 getDepartment 注释掉。运行测试,控制台中竟然打印了查询部门的 sql。说好的延迟加载呢?其实并没有,根本原因就在于,mybatis 认为,toString 里会用到 department 字段,所以触发了查询部门。那么,我们如何改变这种行为呢?mybatis 提供了配置项 lazyLoadTriggerMethods。我们将配置修改如下。再次测试上面的例子。这时,嵌套对象就没有被加载出来了。作为延迟加载部分的总结,这里对比下不同配置项组合的效果。
如果我希望部分关联对象不用延迟加载,部分关联对象又需要,例如,查询员工对象时,部门跟着查出来,而角色等到需要用的时候再加载。针对这种情况,可以使用 fetchType 来覆盖全局配置。
mybatis 的结果集自动映射默认是开启的,可以使用 setting 配置项进行修改。它有三种自动映射等级。上面的 xml 中,如果你的自动映射等级为 PARTIAL,则会出现这样的结果。所以,我强烈建议自动映射等级配置为 FULL。另外,无论是否在全局开启了自动映射,你都可以通过 autoMapping 属性进行覆盖。
以上补充了一些 mybatis 的“彩蛋”,后续发现其他有趣的地方还会继续补充,也欢迎大家指正不足的地方。最后,感谢阅读。