手写MyBatis第31弹-用工厂模式重构MyBatis的SqlSession创建过程
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
MyBatis核心工厂揭秘:SqlSessionFactory如何打造高效的数据库会话生产线
设计模式之美:用工厂模式重构MyBatis的SqlSession创建过程
深入MyBatis源码:解析SqlSessionFactory的重量级身份与创建逻辑
手写MyBatis工厂层:打造可配置化的SqlSession生产体系
架构师视角:为什么SqlSessionFactory是MyBatis中最重量级的组件?
正文
在前两篇文章中,我们实现了SqlSession
的CRUD方法并重构了MapperProxy
,建立了清晰的执行链路。然而,一个关键问题尚未解决:SqlSession
实例应该如何被创建和管理?今天,我们将引入MyBatis架构中的另一个核心组件——SqlSessionFactory
,通过工厂模式来优雅地解决这个问题。
一、为何需要SqlSessionFactory:创建逻辑的封装与复用
直接使用new DefaultSqlSession(configuration, executor)
来创建会话虽然可行,但存在诸多问题:
创建逻辑复杂:一个完整的
SqlSession
创建需要组装Configuration
、Executor
以及可能的事务管理器和连接对象,这些细节不应该暴露给客户端代码。配置一致性:确保所有
SqlSession
实例使用相同的配置基础,避免因配置不一致导致的难以排查的问题。资源管理:集中管理
Executor
的创建和配置,便于实现执行器类型的可配置化。扩展性:为未来支持不同类型的
SqlSession
(如批处理会话、管理型会话)预留扩展点。
工厂模式正是解决这些问题的利器。它通过提供一个专门的工厂类来封装对象的创建逻辑,让客户端无需关心具体的创建细节。
二、SqlSessionFactory的架构设计与实现
让我们通过一个架构图来全面了解SqlSessionFactory
在整体框架中的位置和作用:
从上图可以看出,SqlSessionFactory
作为整个框架的配置中心和生产中心,处于承上启下的关键位置。
第一步:定义SqlSessionFactory接口
public interface SqlSessionFactory {/*** 打开一个SqlSession,使用默认的配置*/SqlSession openSession();/*** 指定是否自动提交事务*/SqlSession openSession(boolean autoCommit);/*** 指定连接对象,用于与现有事务集成*/SqlSession openSession(Connection connection);/*** 指定事务隔离级别*/SqlSession openSession(TransactionIsolationLevel level);/*** 获取配置信息*/Configuration getConfiguration();}
第二步:实现DefaultSqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory {private final Configuration configuration;public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}@Overridepublic SqlSession openSession() {return openSession(false); // 默认非自动提交}@Overridepublic SqlSession openSession(boolean autoCommit) {// 创建事务Transaction tx = null;try {Environment environment = configuration.getEnvironment();TransactionFactory transactionFactory = environment.getTransactionFactory();tx = transactionFactory.newTransaction(environment.getDataSource(), autoCommit);// 创建执行器Executor executor = new SimpleExecutor(configuration, tx);// 创建SqlSessionreturn new DefaultSqlSession(configuration, executor);} catch (Exception e) {// 关闭事务如果创建失败if (tx != null) {tx.close();}throw new RuntimeException("Error opening session. Cause: " + e);}}@Overridepublic SqlSession openSession(Connection connection) {// 基于现有连接创建事务和执行器Transaction tx = new ManagedTransaction(connection);Executor executor = new SimpleExecutor(configuration, tx);return new DefaultSqlSession(configuration, executor);}@Overridepublic SqlSession openSession(TransactionIsolationLevel level) {// 实现略:创建指定隔离级别的事务return openSession(false);}@Overridepublic Configuration getConfiguration() {return configuration;}}
三、为什么SqlSessionFactory是重量级的?
从上面的实现可以看出,SqlSessionFactory
的重量级体现在以下几个方面:
配置信息承载者:它持有
Configuration
对象,这个对象包含了MyBatis运行所需的所有配置信息:数据源、映射器、类型处理器、插件等。这些配置在应用生命周期内通常不会改变。资源初始化成本高:
Configuration
的初始化过程需要解析XML配置、扫描注解、注册映射器等,这些都是相对耗时的操作。线程安全要求:作为共享组件,
SqlSessionFactory
必须是线程安全的,这增加了其实现的复杂性。长生命周期:通常一个应用对应一个
SqlSessionFactory
实例,伴随应用的整个生命周期。
正因为这些特性,我们应该将SqlSessionFactory
设计为单例,在应用启动时创建,在整个运行期间重复使用。
四、Executor的类型配置与选择
Executor
是MyBatis执行SQL的核心组件,不同的执行器类型适应不同的场景:
public enum ExecutorType {SIMPLE, // 简单执行器:每次执行都会创建新的PreparedStatementREUSE, // 复用执行器:复用PreparedStatementBATCH // 批处理执行器:批量执行更新操作}
在SqlSessionFactory
中,我们可以通过配置来决定创建哪种类型的执行器:
// 在openSession方法中根据配置创建不同类型的执行器Executor executor;if (ExecutorType.BATCH == configuration.getDefaultExecutorType()) {executor = new BatchExecutor(configuration, tx);} else if (ExecutorType.REUSE == configuration.getDefaultExecutorType()) {executor = new ReuseExecutor(configuration, tx);} else {executor = new SimpleExecutor(configuration, tx);}// 还可以支持在openSession时指定执行器类型public SqlSession openSession(ExecutorType execType) {Transaction tx = createTransaction();Executor executor = createExecutor(tx, execType);return new DefaultSqlSession(configuration, executor);}
五、SqlSessionFactory的构建者:SqlSessionFactoryBuilder
为了进一步分离关注点,我们引入SqlSessionFactoryBuilder
来专门负责SqlSessionFactory
的构建:
public class SqlSessionFactoryBuilder {public SqlSessionFactory build(Configuration configuration) {return new DefaultSqlSessionFactory(configuration);}public SqlSessionFactory build(InputStream inputStream) {// 解析XML配置,构建Configuration,然后创建SqlSessionFactoryXMLConfigBuilder parser = new XMLConfigBuilder(inputStream);Configuration config = parser.parse();return build(config);}public SqlSessionFactory build(Reader reader) {// 类似上面,从Reader读取配置// ...}}
这种构建者模式的优势在于:
分离配置解析与工厂创建:让每个类职责更加单一
支持多种配置源:可以支持XML、Properties、编程式配置等多种方式
灵活的构建过程:可以在构建过程中添加验证、优化等逻辑
六、总结与最佳实践
通过引入SqlSessionFactory
,我们完成了MyBatis核心架构的又一个重要模块。工厂模式的应用让我们的框架更加专业和灵活:
创建逻辑封装:将复杂的
SqlSession
创建过程封装在工厂中,客户端代码更加简洁配置集中管理:通过
SqlSessionFactory
统一管理所有配置,确保一致性灵活的会话控制:支持创建具有不同特性的
SqlSession
实例更好的资源管理:集中管理
Executor
的创建和生命周期
在实际应用中,我们应该遵循以下最佳实践:
将
SqlSessionFactory
作为应用级单例管理根据具体场景选择合适的
ExecutorType
(批处理操作使用BATCH
,高并发查询考虑REUSE
)通过
SqlSessionFactoryBuilder
统一构建工厂实例,确保配置的一致性
下次当你使用MyBatis时,不妨思考一下:每一个简单的getMapper()
调用背后,是整个工厂体系在默默支撑。这种精妙的分层设计和职责划分,正是优秀框架的迷人之处。
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕我是程序员扣棣,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!