• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Mybatis源码主流程分析

武飞扬头像
juejin
帮助136

背景介绍

Mybatis 是一个 Data Mapper Framework,属于 ORM 框架;旨在提供更简单,更方便地完成操作数据库功能,减轻开发⼈员的⼯作量,消除程序冗余代码。

功能框架

主要从功能⽅面配合源码进行解析 Mybatis 的实现过程和原理,功能框架图如下:

接⼝层:

  1. 使用 Mybatis 提供 API 操作数据库,传递 statementId 和参数 map 给 sqlSession;

  2. 使⽤ mapper 接⼝⽅式操作数据库,每个接⼝口⽅方法对应⼀一个 mapper 节点<insert/select/update/delete>;

处理层:

  1. 处理传入参数,同时进行类型转换 —— ParameterHandler 分析

  2. 根据传入参数,使⽤ ognl 动态生成 SQL 语句 —— StatementHandler 分析

  3. 将 SQL 语句和参数交于执行器进⾏获取结果 —— Executor 分析

  4. 处理结果集,类型转换 —— ResultSetHandler 分析

框架层:

  1. 数据源和连接池管理理 —— 数据源与连接池分析

  2. 事务管理理 —— 事务分析

  3. 缓存管理理(⼀级缓存和二级缓存) —— 缓存分析

  4. SQL 语句配置⽅式管理(XML和注解) —— 配置⽅方式分析

Mybatis 中⽐较核心重要且常⽤的类

  • Configuration MyBatis 所有的配置信息都维持在 Configuration 对象之中。
  • TypeHandler 负责 java 数据类型和 jdbc 数据类型之间的映射和转换。
  • MappedStatement 维护了一条 <select|update|delete|insert> 节点的封装。
  • StatementHandler 封装了 JDBC Statement 操作,负责对 JDBC statement 的操作,如设置参数、将 Statement 结果集转换成 List 集合。
  • ParameterHandler 负责对⽤户传递的参数转换成 JDBC Statement 所需要的参数。
  • SqlSource 负责根据用户传递的 parameterObject,动态地生成 SQL 语句,将信息封装到 BoundSql 对象中,并返回。
  • BoundSql 表示动态生成的 SQL 语句以及相应的参数信息。
  • Executor Mybatis 执行器,是 Mybatis 调度的核心,负责 SQL 语句的生成和查询缓存的维护工作。
  • SqlSession 作为 Mybatis 工作的主要顶层 API,表示和数据库交互的会话,完成必要数据库增删改查功能。
  • ResultSetHandler 负责将 JDBC 返回的 ResultSet 结果集对象转换成 List 类型的集合。

Mybatis 使用

 // 1.初始化 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); inputStream.close();  // 2.获取sqlSession对象 SqlSession session = sqlSessionFactory.openSession();  // 3.获取dao代理对象 DspUserDao dspUserDao = session.getMapper(DspUserDao.class);  // 4.执行sql DspUser user = dspUserDao.selectUserByName("test"); System.out.println(user.getUserName()); 

源码分析

配置文件初始化流程

1. SqlSessionFactoryBuilder

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 

SqlSessionFactoryBuilder 为⼊口点进行传⼊解析 xml。

2. XMLConfigBuilder

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); build(parser.parse()); 

将 XML 进⾏节点解析,封装为 configuration 对象。

 private void parseConfiguration(XNode root) {      try {          // 解析properties         this.propertiesElement(root.evalNode("properties"));         // 解析settings,设置默认值         Properties settings = this.settingsAsProperties(root.evalNode("settings"));          this.loadCustomVfs(settings);         // 解析typeAliases,设置别名          this.typeAliasesElement(root.evalNode("typeAliases"));         // plugins,设置拦截器链         this.pluginElement(root.evalNode("plugins"));          this.objectFactoryElement(root.evalNode("objectFactory"));          this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); this.reflectorFactoryElement(root.evalNode("reflectorFactory")); this.settingsElement(settings);         // environments,设置数据源,tx相关信息          this.environmentsElement(root.evalNode("environments"));          this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));         // 解析typeHandlers,类型处理类          this.typeHandlerElement(root.evalNode("typeHandlers"));         // 解析mapper,处理sql相关信息         this.mapperElement(root.evalNode("mappers"));          } catch (Exception var3) {             throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: "   var3, var3);          } } 

3.sql.xml解析⼊口

 public void parse() {     if (!this.configuration.isResourceLoaded(this.resource)) {          this.configurationElement(this.parser.evalNode("/mapper"));//Map<String, MappedStatement> mappedStatements          this.configuration.addLoadedResource(this.resource);         this.bindMapperForNamespace();//Map<Class<?>, MapperProxyFactory<?>> knownMappers      }      this.parsePendingResultMaps();      this.parsePendingCacheRefs();      this.parsePendingStatements();  }  

获取 sqlSession 流程

1. DefaultSqlSessionFactory

 public SqlSession openSession() {     return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);  } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {      Transaction tx = null;      DefaultSqlSession var8;      try {          Environment environment = this.configuration.getEnvironment();         TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);         tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);          Executor executor = this.configuration.newExecutor(tx, execType);         var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);      } catch (Exception var12) {         this.closeTransaction(tx);         throw ExceptionFactory.wrapException("Error opening session. Cause: "   var12, var12);      } finally {         ErrorContext.instance().reset();      }      return var8; } 

2. configuration创建executor对象

 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {  executorType = executorType == null ? this.defaultExecutorType : executorType;  executorType = executorType == null ? ExecutorType.SIMPLE : executorType;  Object executor;      if (ExecutorType.BATCH == executorType) {         executor = new BatchExecutor(this, transaction);      } else if (ExecutorType.REUSE == executorType) {          executor = new ReuseExecutor(this, transaction);      } else {         executor = new SimpleExecutor(this, transaction);      }      if (this.cacheEnabled) {         executor = new CachingExecutor((Executor)executor);      }      // 此处拦截器调用链加载     Executor executor = (Executor)this.interceptorChain.pluginAll(executor);      return executor; }  

获取 dao 代理理对象流程

1. DefaultSqlSession获取mapper代理理对象

 public <T> T getMapper(Class<T> type) {     return this.configuration.getMapper(type, this);  } public <T> T getMapper(Class<T> type, SqlSession sqlSession) {      return this.mapperRegistry.getMapper(type, sqlSession);  }  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {     MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);      if (mapperProxyFactory == null) {          throw new BindingException("Type "   type   " is not known to the MapperRegistry.");      } else {          try {             return mapperProxyFactory.newInstance(sqlSession);          } catch (Exception var5) {             throw new BindingException("Error getting mapper instance. Cause: "   var5, var5);          }  } 

2. MapperProxyFactory 创建 mapperProxy 的代理理对象

 protected T newInstance(MapperProxy<T> mapperProxy) {     return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);  }  public T newInstance(SqlSession sqlSession) {     MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);      return this.newInstance(mapperProxy);  } 

执行查询流程

1. mapperProxy 代理理对象调⽤用 invoke

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {      try {          // 若执⾏的object类的方法,直接调⽤         if (Object.class.equals(method.getDeclaringClass())) {              return method.invoke(this, args);           }          if (this.isDefaultMethod(method)) {             return this.invokeDefaultMethod(proxy, method, args);          }      } catch (Throwable var5) {          throw ExceptionUtil.unwrapThrowable(var5);       }       // 缓存中获取MapperMethod     MapperMethod mapperMethod = this.cachedMapperMethod(method);     return mapperMethod.execute(this.sqlSession, args); } 

2. 创建 MapperMethod 执⾏操作

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {     this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);     this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);  }  // 根据sql类型进⾏执行 public Object execute(SqlSession sqlSession, Object[] args){      ....省略      param = this.method.convertArgsToSqlCommandParam(args);      result = sqlSession.selectOne(this.command.getName(), param);      ....省略  } 

3. DefaultSqlSession 执⾏ select 操作

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {     List var5;      try {         // 从configuration中获取MappedStatement对象          MappedStatement ms = this.configuration.getMappedStatement(statement);         // 通过executor执行MappedStatement         var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);      } catch (Exception var9) {         throw ExceptionFactory.wrapException("Error querying database. Cause: "   var9, var9);      } finally {          ErrorContext.instance().reset();      }      return var5;  } 

4. Executor

baseExecutor类

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {     // 获取动态⽣成的SQL语句以及相应的参数信息     BoundSql boundSql = ms.getBoundSql(parameter);     // 缓存当前查询      CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);      return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);  }  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {     ....省略     // simpleExecutor执⾏查询      list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);      ....省略  }

simpleExecutor类

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {     Statement stmt = null;      List var9;      try {          Configuration configuration = ms.getConfiguration();          // 创建PreparedStatementHandler预编译处理类,包含parameterHandler和resultSetHandler         StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);          // 设置参数信息         stmt = this.prepareStatement(handler, ms.getStatementLog());         // 执⾏行行sql,并处理理结果集         var9 = handler.query(stmt, resultHandler);      } finally {          this.closeStatement(stmt);      }      return var9;  } 

5.创建StatementHandler

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {      // 创建PreparedStatementHandler预编译处理类,包含parameterHandler和resultSetHandler     StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);      StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);     return statementHandler;  } 

6.parameterHandler设置参数信息

public void parameterize(Statement statement) throws SQLException {     this.parameterHandler.setParameters((PreparedStatement)statement);  } 

7. PreparedStatementHandler执行sql,并处理结果集

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {      PreparedStatement ps = (PreparedStatement)statement;     ps.execute();     return this.resultSetHandler.handleResultSets(ps);  }

总结

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/taneiij
系列文章
更多 icon
同类精品
更多 icon
继续加载