01、前言
根据 Mybatis SQL 执行流程图进一步了解
02、Mybatis Sql 的执行过程
大致可以分为以下几步操作:
📖 在前面的内容中, 知道了 Mybatis Mapper 是动态代理的实现, 查看 SQL 执行过程, 就需要紧跟实现了 InvocationHandler 的 MapperProxy 类
03、执行增删改查
@Select(" SELECT * FROM SUBJECT WHERE ID = #{id}")
PrimitiveSubject getSubject(@Param("id") final int id);
我们以上述方法举例, 调用方通过 SqlSession 获取 Mapper 动态代理对象, 执行 Mapper 方法时会通过 InvocationHandler 进行代理
在 MapperMethod#execute 中, 根据 MapperMethod -> SqlCommand -> SqlCommandType 来确定增、删、改、查方法
📖 SqlCommandType 是一个枚举类型, 对应五种类型 UNKNOWN、INSERT、UPDATE、DELETE、SELECT、FLUSH
04、参数处理
查询操作对应 SELECT 枚举值, if else 中判断为返回值是否集合、无返回值、单条查询等, 这里以查询单条记录作为入口
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
📖 这里能够解释一个之前困扰我的问题, 那就是为什么方法入参只有单个
@Param("id")
, 但是参数 param 对象会存在两个键值对
继续查看 SqlSession#selectOne 方法, sqlSession 是一个接口, 具体还是要看实现类 DefaultSqlSession
因为单条和查询多条以及分页查询都是走的一个方法, 所以在查询的过程中, 会将分页的参数进行添加
05、执行器处理
在 Mybatis 源码中, 创建的执行器默认是 CachingExecutor, 使用了装饰者模式, 在类中保持了 Executor 接口的引用, CachingExecutor 在持有的执行器基础上增加了缓存的功能
delegate.query 就是在具体的执行器了, 默认 SimpleExecutor, query 方法统一在抽象父类 BaseExecutor 中维护
BaseExecutor#queryFromDatabase 方法执行了缓存占位符以及执行具体方法, 并将查询返回数据添加至缓存
BaseExecutor#doQuery 方法是由具体的 SimpleExecutor 实现
06、执行 SQL
因为我们 SQL 中使用了参数占位符, 使用的是 PreparedStatementHandler 对象, 执行预编译SQL的 Handler, 实际使用 PreparedStatement 进行 SQL 调用
07、返回数据解析
将 JDBC 返回类型转换为 Java 类型, 根据 resultSets 和 resultMap 进行转换