Mybatis查询源代码分析

mybatis 作为常用的 orm 框架,极大的简化了我们手写jdbc代码的情况,其中它的设计还是蛮有意思的

jdbc 执行查询

在不使用 mybatis 的情况下,使用刚入门的 jdbc 执行一次查询的过程如下

  1. public class App {
  2. public static void main(String[] args) throws Exception {
  3. Connection connection = DriverManager.getConnection("xx", null);
  4. PreparedStatement preparedStatement = connection.prepareStatement("select * from `user` where id = ?");
  5. preparedStatement.setInt(1, 1);
  6. preparedStatement.execute();
  7. ResultSet resultSet = getFirstResult(preparedStatement);
  8. if (resultSet != null) {
  9. while (resultSet.next()) {
  10. //获取 pojo 对象
  11. User user = new User();
  12. ...//填充数据
  13. }
  14. }
  15. }
  16. private static ResultSet getFirstResult(Statement statement) throws SQLException {
  17. ResultSet resultSet = statement.getResultSet();
  18. while (resultSet == null) {
  19. if (statement.getMoreResults()) {
  20. resultSet = statement.getResultSet();
  21. } else {
  22. if (statement.getUpdateCount() == -1) {
  23. // no more results. Must be no resultset
  24. break;
  25. }
  26. }
  27. }
  28. return resultSet;
  29. }

这个过程基本上可以概括为如下

  • 获取物理链接(Connection) ——> 第三行
  • 预编译 ——> 第四行,设置resultSet参数
  • 设置参数 + 执行sql ——> 第五行+第六行
  • 处理结果集 ——> 第7行到结束

整个 mybatis 的处理流程也是一致的,从根本上简化了我们写jdbc的代码,同时也带来了一定的损耗(相对于jdbc而言),但是这点损耗和维护性来说,是值得接受的

mybatis 执行查询

mybatis 执行一次查询的过程如下

  • 读取配置文件,获取 SqlSessionFactoryBuilder
  • 解析配置文件,获取 SqlSessionFactory
    • 解析 configuration.xml
      • 解析配置的属性元素,例如 cacheEnabled localCacheScope , 解析别名等等。
      • 解析 mapper.xml 文件
        • 解析 ResultMap , paratemerMap sql curd 节点,为每一个curd节点配置一个MappedStatement对象
  • 获取 SqlSession—> sqlSessionFactory.openSession(xxxx)
  • 事务 TransactionFactory
  • 执行器 Executor
  • new DefaultSqlSession(configuration, executor, autoCommit)
  • 执行 mybatis 方法 ——> performDataDao.selectPerformDataByKey(1234571443)
    • 获取对应 statementIdMappedStatement 对象委托给executor#query 继续执行
    • 跳过缓存,查询db,获取PreparedStatementHandler,执行预编译,设置参数
      • 预编译 connection.prepareStatement(sql) —-> PreparedStatementHandler#instantiateStatement
      • 设置参数 preparedStatement.setInt(1, 1); —-> DefaultParameterHandler#setParameters,将包转过的参数根据parameterType/Map设置
    • 执行查询,处理结果集合
      • 反射获取 pojo 对象,填充参数

整个流程不算清晰,但是也能大致的说明 mybatis 的执行过程,具体可分为 解析配置文件 请求处理器 请求处理后

  • 解析配置文件
    • configuration.xml 和 mapper,xmlconfiguration 对象的参数填充
    • MappedStatement 对象的填充,Resultmap 解析,Sql 节点解析 等等
  • 请求处理前
    • 预编译,设置参数,设置超时时间,设置fetchSize,设置ResultSetType
  • 请求处理后
    • 处理结果集,RowBound 处理,ResultMap处理(反射pojo,参数填充)

解析配置文件

请求处理前

请求处理后

小结

2018-10-22