手写MyBatis第36弹:MyBatis执行流程中SQL命令类型解析
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
目录
1 SQL命令类型概述与重要性
2 XML配置方式解析SQL命令类型
2.1 解析过程与关键代码
2.2 XML配置示例
3 注解方式解析SQL命令类型
3.1 注解解析过程
3.2 注解配置示例
4 MappedStatement的创建与SQL命令类型的设置
5 SQL命令类型在Executor中的使用
5.1 执行路由决策
5.2 其他影响
6 总结
MyBatis SQL命令类型解析:从注解与XML到MappedStatement的奥秘
-
《MyBatis SQL命令类型解析:揭秘@Select/@Insert与XML节点的执行决策依据》
-
《深入MyBatis内核:SQL操作类型如何影响Executor的行为路径》
-
《手写MyBatis(七):解析SQL命令类型,奠定执行决策基石》
-
《从注解/XML到MappedStatement:MyBatis如何确定你的SQL要做什么?》
-
《SQL命令类型的奥秘:MyBatis执行流程中的关键枚举值》
MyBatis作为一个优秀的持久层框架,其核心功能之一便是将开发者编写的SQL语句(无论是通过XML还是注解方式)转化为对数据库的实际操作。在这个过程中,准确识别SQL语句的类型(SELECT
, INSERT
, UPDATE
, DELETE
)至关重要,因为它直接决定了MyBatis底层执行引擎的行为路径。本文将深入剖析MyBatis如何解析并确定SQL命令类型,并探讨这一信息在后续执行流程中的关键作用。
1 SQL命令类型概述与重要性
在MyBatis中,SqlCommandType
是一个枚举类型,它定义了以下几种SQL操作类型:
-
SELECT
:对应查询操作,用于从数据库检索数据。 -
INSERT
:对应插入操作,用于向数据库插入新数据。 -
UPDATE
:对应更新操作,用于更新数据库中的现有数据。 -
DELETE
:对应删除操作,用于从数据库中删除数据。 -
(还有其他如
FLUSH
等较少用的类型)
MappedStatement
对象是 MyBatis 框架的核心类之一,它存储了一个 SQL 对应的所有信息。其 sqlCommandType
属性记录了该 SQL 语句的操作类型。明确记录每条SQL语句的操作类型,是执行时决策(如调用Executor.query
还是Executor.update
)的依据。
SQL命令类型的重要性主要体现在以下几个方面:
-
执行路由决策:MyBatis的
Executor
会根据sqlCommandType
来决定是调用doUpdate
方法还是doQuery
方法。 -
缓存行为控制:例如,
SELECT
语句通常会查询缓存,而INSERT
、UPDATE
、DELETE
语句则可能刷新缓存(根据配置)。 -
主键生成处理:
INSERT
操作可能需要处理自增主键或序列主键的获取。 -
事务语义理解:虽然事务通常由外部管理,但了解操作类型有助于理解数据变更的边界。
2 XML配置方式解析SQL命令类型
当MyBatis解析XML映射文件时,会根据SQL语句所在的XML节点名称来确定其命令类型。
2.1 解析过程与关键代码
MyBatis通过XMLStatementBuilder
类来解析XML中的SQL节点。解析过程中,会提取节点的名称,并将其转换为对应的SqlCommandType
。
public class XMLStatementBuilder {public void parseStatementNode() {// 获取XML节点的名称,如 "select", "insert", "update", "delete"String nodeName = context.getNode().getNodeName();// 将节点名称转换为大写,并匹配到SqlCommandType枚举值SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));// ... 后续构建MappedStatement时,会使用这个sqlCommandType}}
2.2 XML配置示例
以下是一个XML映射文件的示例,展示了不同类型的SQL语句:
<mapper namespace="com.example.MyMapper"><select id="selectUser" resultType="User">SELECT * FROM user WHERE id = #{id}</select><insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">INSERT INTO user (name, email) VALUES (#{name}, #{email})</insert><update id="updateUser" parameterType="User">UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id}</update><delete id="deleteUser" parameterType="int">DELETE FROM user WHERE id = #{id}</delete></mapper>
MyBatis在解析上述XML文件时,会根据<select>
、<insert>
、<update>
、<delete>
这些节点名称,分别创建SqlCommandType
为SELECT
、INSERT
、UPDATE
、DELETE
的MappedStatement
对象。
3 注解方式解析SQL命令类型
对于使用注解配置的SQL语句,MyBatis通过MapperAnnotationBuilder
来解析方法上的注解,并确定其SQL命令类型。
3.1 注解解析过程
MyBatis支持的SQL注解包括@Select
、@Insert
、@Update
、@Delete
等。解析器会检查方法上的注解,并根据注解类型来确定SQL命令类型。
public class MapperAnnotationBuilder {private void parseStatement(Method method) {// 获取方法上的注解Annotation annotation = findAnnotation(method, Select.class, Insert.class, Update.class, Delete.class, ...);SqlCommandType sqlCommandType;if (annotation instanceof Select) {sqlCommandType = SqlCommandType.SELECT;} else if (annotation instanceof Insert) {sqlCommandType = SqlCommandType.INSERT;} else if (annotation instanceof Update) {sqlCommandType = SqlCommandType.UPDATE;} else if (annotation instanceof Delete) {sqlCommandType = SqlCommandType.DELETE;} else {// 处理其他情况或报错}// ... 使用sqlCommandType构建MappedStatement}}
3.2 注解配置示例
public interface UserMapper {@Select("SELECT * FROM users WHERE id = #{id}")User selectUserById(int id);@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")@Options(useGeneratedKeys = true, keyProperty = "id")int insertUser(User user);@Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")int updateUser(User user);@Delete("DELETE FROM users WHERE id = #{id}")int deleteUser(int id);}
当MyBatis解析UserMapper
接口时,它会读取每个方法上的注解,并根据注解类型(@Select
, @Insert
, @Update
, @Delete
)为每个方法对应的MappedStatement
设置相应的SqlCommandType
。
4 MappedStatement的创建与SQL命令类型的设置
无论是通过XML还是注解方式解析,最终都会构建一个MappedStatement
对象,其中包含了该SQL语句的所有配置信息,包括sqlCommandType
。
MappedStatement
对象通过 Builder
模式创建,并在构建过程中设置其属性,包括 sqlCommandType
。
MappedStatement
的关键属性包括:
-
id
:通常由命名空间和方法名组成,唯一标识一个MappedStatement。 -
sqlSource
:表示解析出来的SQL。 -
sqlCommandType
:SQL命令类型(SELECT, INSERT, UPDATE, DELETE等)。 -
parameterType
:参数类型。 -
resultType
/resultMap
:结果类型或结果映射。 -
useCache
、flushCache
等缓存相关属性。
5 SQL命令类型在Executor中的使用
SQL命令类型(sqlCommandType
)信息在Executor
的执行方法中被使用,它是决定调用Executor
的query
方法还是update
方法的关键依据。
5.1 执行路由决策
当通过SqlSession
调用一个Mapper方法时,MyBatis会找到对应的MappedStatement
,并根据其sqlCommandType
来决定执行路径:
public class CachingExecutor implements Executor {@Overridepublic <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {// ... 处理查询操作(SELECT语句)}@Overridepublic int update(MappedStatement ms, Object parameterObject) throws SQLException {// ... 处理更新操作(INSERT, UPDATE, DELETE语句)}}
在DefaultSqlSession
中,你可以看到根据sqlCommandType
进行路由的逻辑:
public class DefaultSqlSession implements SqlSession {@Overridepublic int insert(String statement, Object parameter) {return update(statement, parameter);}@Overridepublic int update(String statement, Object parameter) {// 对于INSERT, UPDATE, DELETE语句,最终都调用update方法MappedStatement ms = configuration.getMappedStatement(statement);return executor.update(ms, wrapCollection(parameter));}@Overridepublic <E> List<E> selectList(String statement, Object parameter) {// 对于SELECT语句,调用query方法MappedStatement ms = configuration.getMappedStatement(statement);return executor.query(ms, wrapCollection(parameter), RowBounds.DEFAULT, null);}}
值得注意的是,虽然SqlSession
提供了insert
, update
, delete
等不同方法,但在MyBatis底层,INSERT
, UPDATE
, DELETE
操作最终都调用Executor.update
方法,而SELECT
操作则调用Executor.query
方法。这是因为从数据库的角度来看,INSERT
、UPDATE
、DELETE
都是写操作,会改变数据库状态,而SELECT
是读操作。
5.2 其他影响
除了决定调用query
还是update
方法外,sqlCommandType
还会影响:
-
缓存行为:
SELECT
语句的结果可能会被缓存(根据配置),而写操作通常会刷新缓存。 -
事务管理:虽然事务通常由外部管理,但了解操作类型有助于理解数据变更的边界。
-
主键生成:对于
INSERT
语句,MyBatis可能会在处理后获取自增主键值并设置回参数对象。
6 总结
SQL命令类型的解析是MyBatis执行流程中的基础环节,它架起了开发者编写的SQL语句与底层数据库操作之间的桥梁。通过深入了解SqlCommandType
的解析过程和作用机制,我们不仅能更好地理解MyBatis的内部工作原理,也能在遇到问题时更快地定位和解决。
无论是XML配置还是注解配置,MyBatis都提供了一致的机制来解析和确定SQL命令类型,并将其封装在MappedStatement
对象中。最终,这一信息在Executor
的执行方法中被关键性地使用,决定了SQL语句的执行路径和行为,确保了MyBatis能够正确、高效地处理各种数据库操作。
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕我是程序员扣棣,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!