手写MyBatis第40弹:手写MyBatis框架阶段性总结,你的ORM框架已达生产级雏形
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
目录
一、当前框架状态:我们实现了什么?
二、核心组件回顾:齿轮如何啮合?
三、架构演进思考:下一步迈向何方?
四、总结
-
从零构建MyBatis:我们的轮子已经能跑了!核心架构全解析与未来展望
-
手写MyBatis完结篇?不,是新征程的起点:回顾CRUD实现,展望插件与缓存
-
深入理解MyBatis架构:通过手写实践,彻底掌握其核心组件的职责与协作
-
造轮子的艺术:手写MyBatis框架阶段性总结,你的ORM框架已达生产级雏形
在经历了前面数篇从解析配置、创建代理、执行SQL到处理结果集的深入剖析与实践后,我们亲手打造的“迷你MyBatis”框架已经完成了它的第一次蜕变。它不再是一个简单的概念验证(Proof of Concept),而是一个具备了完整CRUD操作能力的ORM框架雏形。此刻,让我们暂时停下编码的脚步,站在一个更高的视角来审视我们的作品,回顾其核心架构与数据流,并思考它未来的演进方向。
一、当前框架状态:我们实现了什么?
我们的框架已经支持了两种经典的数据操作方式,覆盖了完整的CRUD功能:
-
优雅的Mapper代理接口方式(面向接口编程): 这是MyBatis推荐的用法。用户只需定义一个Java接口,我们的框架通过动态代理技术(
MapperProxy
)自动生成其实现。开发者获得了完全的类型安全性和IDE的支持,体验如同调用本地方法一样自然。UserMapper userMapper = sqlSession.getMapper(UserMapper.class);User user = userMapper.selectUserById(1);userMapper.updateUser(user);
-
灵活的直接
SqlSession
API方式: 这种方式提供了更直接的控制力。用户通过传入Statement ID(通常是namespace.id
的形式)和参数来执行操作,虽然牺牲了一些类型安全,但在某些需要动态构建SQL的场景下更为灵活。User user = sqlSession.selectOne("com.example.mapper.UserMapper.selectUserById", 1);int count = sqlSession.update("com.example.mapper.UserMapper.updateUser", user);
这两种方式虽然在入口上有所不同,但最终都汇入了同一套核心执行流程,共享着相同的底层组件。
二、核心组件回顾:齿轮如何啮合?
我们的框架之所以能够运转起来,全靠内部各个核心组件各司其职、精密协作。它们共同构成了框架的骨架与神经。
-
SqlSessionFactoryBuilder
: 工厂的建造者。-
职责: 生命周期始于配置解析,终于工厂创建。它读取XML配置文件或代码配置,构建出庞大的
Configuration
对象,并以此创建唯一的SqlSessionFactory
,功成身退。
-
-
SqlSessionFactory
: 会话的工厂。-
职责: 作为应用程序生命周期内的单例,是生成
SqlSession
的“车间”。它持有全局唯一的Configuration
对象,根据执行器类型(SIMPLE, BATCH等)创建相应的SqlSession
。
-
-
SqlSession
: 面向用户的API门户。-
职责: 是用户与框架交互的主要接口,代表了一次数据库会话。它封装了增删改查等所有数据库操作方法,其内部将工作委托给
Executor
执行。同时,它还管理着事务的提交与回滚。
-
-
Executor
: SQL执行的大脑。-
职责: 是真正的执行调度中心。它定义了
query
和update
等核心方法。我们实现了两种策略:-
SimpleExecutor
:最简单的实现,每次执行都会创建一个新的PreparedStatement
。 -
BatchExecutor
:用于批处理,会将多个操作缓存起来,最后统一执行,极大提升性能。
-
-
它协调
StatementHandler
、ParameterHandler
、ResultSetHandler
共同完成一次数据库操作。
-
-
MapperProxy
: 动态代理的魔术师。-
职责: 是JDK动态代理的
InvocationHandler
实现。当调用Mapper接口方法时,它会拦截调用,将方法名、参数等信息转换为对底层SqlSession
方法的调用(如将selectUserById
转换为sqlSession.selectOne(...)
)。
-
-
MappedStatement
: SQL指令的封装。-
职责: 是映射文件(或注解)中一条SQL语句(如
<select>
)的内存等价物。它被存储在Configuration
中,包含了SQL源码、执行类型、参数类型、结果类型等所有关键信息,是执行操作的“作战计划”。
-
-
Configuration
: 全局配置的仓库。-
职责: 框架的“宇宙中心”,一个贯穿始终的核心对象。它包含了所有的配置信息:数据库环境、Mapper注册表、所有
MappedStatement
、类型处理器等,是框架的全局上下文。
-
-
ParameterHandler
&ResultSetHandler
&TypeHandler
: 数据处理的工匠。-
职责: 这三个组件共同负责Java世界与数据库世界的数据类型转换。
-
ParameterHandler
:负责将JavaBean参数设置到PreparedStatement的占位符?
上。 -
ResultSetHandler
:负责将JDBC返回的ResultSet
结果集转换为我们想要的Java对象(List、Map或单个POJO)。 -
TypeHandler
:是前两者的基础,负责单个Java类型与JDBC类型之间的相互转换。
-
三、架构演进思考:下一步迈向何方?
一个基本可用的框架已经建成,但这远非终点。要将其打造成一个生产级可用的成熟框架,我们还需要考虑以下几个关键方向的扩展:
-
扩展性:插件机制(Interceptor)
-
思考: 如何在不修改核心代码的情况下,允许用户在任何一次数据库操作的关键节点(如执行SQL前、处理参数后、返回结果前)插入自定义逻辑?这就需要设计一个强大的插件拦截机制,这是MyBatis如此灵活的灵魂所在。
-
-
性能:缓存(Cache)与连接池(Pool)
-
思考: 如何避免重复查询?引入一级缓存(SqlSession级别) 和二级缓存(Mapper/Namespace级别) 是必然选择。同时,数据库连接的创建和销毁是昂贵的,集成成熟的数据库连接池(如HikariCP, Druid)来管理连接资源,是提升性能和生产环境健壮性的必备条件。
-
-
健壮性:事务管理(Transaction)
-
思考: 我们虽然引入了
Transaction
接口解耦了连接管理,但事务的传播行为(如REQUIRED, REQUIRES_NEW)、隔离级别等高级特性还需要进一步设计。一个健壮的事务管理器是保证数据一致性的基石。
-
-
灵活性:动态SQL(Dynamic SQL)
-
思考: 目前我们的SQL是静态的。但在实际业务中,SQL往往需要根据参数条件动态变化(
if
,where
,foreach
等)。实现一套动态SQL功能,能够极大解放生产力,避免在Java代码中拼接SQL字符串的繁琐与危险。
-
四、总结
通过这一系列的手写实践,我们不仅仅是在“造轮子”,更是在进行一场深入的MyBatis源码之旅。我们亲手实现了它的核心脉络,对其中每一个组件的职责、每一次数据的流动都有了刻骨铭心的理解。
这个我们亲手搭建的框架,虽然简陋,但已然具备了现代ORM框架的核心骨架。它是对接口驱动、反射、动态代理、设计模式(如建造者、工厂、代理、模板方法)、资源管理、事务控制等一系列Java高级编程技术的综合运用与深刻体现。
回顾来时路,繁花已似锦;展望未来途,星晨正可期。接下来,就让我们带着这些思考,继续深入,为我们的框架注入插件、缓存、事务的灵魂,让它变得更加强大和优雅。征程,还在继续。
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕我是程序员扣棣,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!