Mybatis的解析和运行原理概述

Mybatis的解析和运行原理

  1. mybatis解析配置文件的主要过程
  2. mybatis底层映射保存的数据结构(MappedStatement、SqlSource、BoundSql)
  3. Mybatis Mapper的运行原理
  4. SqlSession运行原理
  5. SqlSession下四大对象的设计原理和具体方法的作用
  • mybatis运行过程

    • 读取mybatis配置文件配置缓存到Configuration对象,用来创建SqlSessionFactory
    • SqlSession的执行过程
  • 构建SqlSessionFactory的过程(Builder模式)

    • 第1步:通过XMLConfigBuilder解析配置xml文件中所配置的参数,存入Configuration对象中

      • Configuration采用的是单例模式
    • 第2步:使用Configuration创建SqlSessionFactory。mybatis中的SqlSessionFactory是一个接口,它的实现类是DefaultSqlSessionFactory

    • XMLConfigBuilder解析xml源码

      • public class XMLConfigBuilder extends BaseBuilder{
            public void parseConfiguration(XNode root){
        		......
                    typeHandlerElement(root.evalNode("typeHandlers"));
                ......
            }
        }
        
    • 通过上述源码可了解XMLConfigBuilder通过一步步解析xml的内容得到对应的配置文件内容中的信息。

    • 以typeHandlers配置为例说明:

      • 配置的typeHandler都会被注册到typeHandlersRegistry对象中去。typeHandlersRegistry定义在XMLConfigBuilder的父类BaseBuilder中,源码如下

      • public abstract class BaseBuilder{
            protected final Configuration configuration;
            ......
            protected final TypeHandlersRegistry typeHandlersRegistry;
            public BaseBuilder(Configuration configuration){
                this.configuration=configuration;
                this.typeHandlersRegistry=this.configuration.getTypeHandlersRegistry();
            }
            ......
        }
        
      • TypeHandlersRegistry是Configuration单例的一个属性

    • 其他配置内容也是用类似上述的方法注册的

  • 构建映射器的内部组成

    • 当XMLConfigBuilder解析XML时,会将每一个SQL和其配置的内容保存起来,mybatis中一条sql和它相关的配置信息是由3个部分组成
      • MappedStatement:保存一个映射器节点(select|insert|delete|update)
      • SqlSource:是MappedStatement的一个重要属性。也是一个接口,有几个实现类。他的作用是根据上下文和参数解析生成需要的SQL,这个接口只定义了一个方法getBoundSql(paramterObject)
      • BoundSql:是一个结果对象。也就是SqlSource解析到的SQL和参数,它是建立SQL和参数的地方。它有三个常用的属性
        • parameterObject:参数本身,可传递对象、pojp、map、@param注解的参数
          • 传递简单参数时,mybatis会把其变为父类对象传递,如int–integer
          • 传递多个参数时,如果没有@param注解。mybatis会把paramObject变为Map<String,Object>对象{“1”:value,“2”:value},可以使用#{1}或#{key}取值
          • 使用@param会把map的key指定为注解中的值
        • parameterMappings
          • 包含了元素为parameterMapping对象的List,parameterMapping描述了属性名称、表达式、javaType、jdbcType、typeHandler等信息,通过它可以实现参数与sql结合。以便PreparedStatement通过它找到parameterObject对象的属性设置参数
        • sql
          • 书写在映射器中的被SqlSource解析后的sql
  • 构建SqlSessionFactory

    • SqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
    • 先根据文件流生成Configuration对象,进而构建SqlSessionFactory对象
  • SqlSession运行过程

    • 映射器Mapper的动态代理

      • xxxMapper xxmappner=sqlSession.getMapper(xxxMapper.class);
        //getMapper-->SqlSession源码
        public class DefaultSqlSession implements SqlSession{
            @Override
            public <T> T getMapper(Class<T> type){
                //调用configuration的getMapper
                return configuration.<T>getMapper(type,this);
            }
        }
        
      
      ```java
      //configuration
      public <T> T getMapper(Class<T> type,SqlSession sqlSession){
          //运用映射器的注册器mapperRegistry来获取对应的接口对象
          return mapperRegistry.getMapper(type,sqlSession);
      }
      ```
      
      ```java
      //MapperRegistry源码片段
      public class MapperRegistry {
          private final Configuration config;
          private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
      
          public MapperRegistry(Configuration config) {
              this.config = config;
          }
      
          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);
                  }
              }
          }
      }
      /**
       *判断是否注册一个Mapper,如果没有则会抛出异常,如果有,就会启用MapperProxyFactory工厂来生成一个代理实例
       */
      ```
      
      ```java
      //MapperProxyFactory生成代理对象
      public class MapperProxyFactory<T> {
          private final Class<T> mapperInterface;
          private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();
      
          public MapperProxyFactory(Class<T> mapperInterface) {
              this.mapperInterface = mapperInterface;
          }
      
          public Class<T> getMapperInterface() {
              return this.mapperInterface;
          }
      
          public Map<Method, MapperMethod> getMethodCache() {
              return this.methodCache;
          }
      	//生成代理对象并调用invoke代理方法
          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);
          }
      }
      ```
      
      ```java
      //调用代理方法源码
      public class MapperProxy<T> implements InvocationHandler, Serializable {
      ......
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              try {
                  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 = this.cachedMapperMethod(method);
              return mapperMethod.execute(this.sqlSession, args);
          }
      ......
      }
      /**
       *如果Mapper是一个jdk动态代理对象,那么它会运行到invoke,invoke首先判断是否是一个类,这里的Mapper是一个接口不是一个类,所以会通过cachedMapperMethod生成MapperMethod对象,最后执行execute方法,把SqlSession和当前运行的参数传递进去
       */
      ```
      
      ```java
      public class MapperMethod {
          private final MapperMethod.SqlCommand command;
          private final MapperMethod.MethodSignature method;
      
          public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
              this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
              this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
          }
      
          public Object execute(SqlSession sqlSession, Object[] args) {
              Object param;
              Object result;
              switch(this.command.getType()) {
              case INSERT:
                  param = this.method.convertArgsToSqlCommandParam(args);
                  result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
                  break;
              case UPDATE:
                  param = this.method.convertArgsToSqlCommandParam(args);
                  result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
                  break;
              case DELETE:
                  param = this.method.convertArgsToSqlCommandParam(args);
                  result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
                  break;
              case SELECT:
                  if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                      this.executeWithResultHandler(sqlSession, args);
                      result = null;
                  } else if (this.method.returnsMany()) {
                      //查询
                      result = this.executeForMany(sqlSession, args);
                  } else if (this.method.returnsMap()) {
                      result = this.executeForMap(sqlSession, args);
                  } else if (this.method.returnsCursor()) {
                      result = this.executeForCursor(sqlSession, args);
                  } else {
                      param = this.method.convertArgsToSqlCommandParam(args);
                      result = sqlSession.selectOne(this.command.getName(), param);
                  }
                  break;
              case FLUSH:
                  result = sqlSession.flushStatements();
                  break;
              default:
                  throw new BindingException("Unknown execution method for: " + this.command.getName());
              }
      
              if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
                  throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
              } else {
                  return result;
              }
          }
         
          private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
              Object param = this.method.convertArgsToSqlCommandParam(args);
              List result;
              if (this.method.hasRowBounds()) {
                  RowBounds rowBounds = this.method.extractRowBounds(args);
                  result = sqlSession.selectList(this.command.getName(), param, rowBounds);
              } else {
                  result = sqlSession.selectList(this.command.getName(), param);
              }
      
              if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
                  return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
              } else {
                  return result;
              }
          }
      }
      ```
  
- **SqlSession下的四大对象**

  - 映射器就是一个动态代理对象进入到了MapperMethod的execute方法,然后经过简单的判断就进入了SqlSession的crud等方法,下面介绍这些方法是如何执行的,这是正确编写插件的根本

  - Executor:执行器,负责调度**StatementHandler**、ParameterHandler、ResultSetHandler来执行对应的SQL

  - StatementHandler:负责使用数据库的Statement(PreparedStatement)执行操作,它是四大对象的核心,起到承上启下的作用,许多重要的插件都是通过拦截它来实现。

  - ParameterHandler:用来处理SQL语句

  - ResultSetHandler:进行数据集(ResultSet)的封装返回处理

  - Executor

    - 执行器:执行java和数据库交互的对象,可以在settings元素中的defaultExecutorType中设置3种执行器

    - 先看看mybatis是如何创建Executor的

    - ```java
      //Configuration.newExecutor
          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);
              }
      
              //mybatis的插件、构建一层层动态代理对象
              Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
              return executor;
          }
      ```

      ```java
      //以Simple执行器为例
      public class SimpleExecutor extends BaseExecutor {
          public SimpleExecutor(Configuration configuration, Transaction transaction) {
              super(configuration, transaction);
          }
      
          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();
                  StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
                  stmt = this.prepareStatement(handler, ms.getStatementLog());
                  //把ResultHandler传递进去,用来组织结果返回给调用者来完成一次查询
                  var9 = handler.query(stmt, resultHandler);
              } finally {
                  this.closeStatement(stmt);
              }
      
              return var9;
          }
          private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
              Connection connection = this.getConnection(statementLog);
              //预编译及基础设置
              Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
              //设置参数
              handler.parameterize(stmt);
              return stmt;
          }
      }
      /**
       *mybatis根据Config来构建StatementHandler,然后使用prepareStatement对sql和参数进行初始化
       */
      ```

  - StatementHandler——数据库会话器

    - 用来处理数据库会话

    - ```java
          public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
              StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
              StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
              return statementHandler;
          }
      ```

      创建的真实对象是RoutingStatementHandler,和Executor一样,用代理对象做一层层封装

      RoutingStatementHandler不是真实的服务对象,它是通过适配模式来找到对应的statementHandler来执行。RoutingStatementHandler分为三种:SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler。它对应的是jdbc的Statement、PreparedStatement(预编译处理)、CallableStatement(存储过程处理)。

      初始化RoutingStatementHandler对象时,会根据上下文环境决定创建哪个具体的StatementHandeler对象实例

      ```java
      public class RoutingStatementHandler implements StatementHandler {
          private final StatementHandler delegate;
      
          public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
              switch(ms.getStatementType()) {
              case STATEMENT:
                  this.delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                  break;
              case PREPARED:
                  this.delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                  break;
              case CALLABLE:
                  this.delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                  break;
              default:
                  throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
              }
          }
      ```

      以PreparedStatementHandler为例。Executor执行查询时会执行StatementHandler的prepare、parameterize、query方法

      ```java
      public abstract class BaseStatementHandler implements StatementHandler {
              public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
              ErrorContext.instance().sql(this.boundSql.getSql());
              Statement statement = null;
      
              try {
                  //对sql进行预编译和基础配置
                  statement = this.instantiateStatement(connection);
                  this.setStatementTimeout(statement, transactionTimeout);
                  this.setFetchSize(statement);
                  return statement;
              } catch (SQLException var5) {
                  this.closeStatement(statement);
                  throw var5;
              } catch (Exception var6) {
                  this.closeStatement(statement);
                  throw new ExecutorException("Error preparing statement.  Cause: " + var6, var6);
              }
          }
      }
      ```

      ```java
      //设置参数
      public class PreparedStatementHandler extends BaseStatementHandler {
      	public void parameterize(Statement statement) throws SQLException {
              this.parameterHandler.setParameters((PreparedStatement)statement);
          }
      }
      ```

      ```java
      //查询方法
      public class PreparedStatementHandler extends BaseStatementHandler {
          public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
              PreparedStatement ps = (PreparedStatement)statement;
              ps.execute();
              return this.resultSetHandler.handleResultSets(ps);
          }
      }
      ```

  - 一条SQL的执行过程:Executor先调用StatementHandler的prepare()方法预编译SQL,同时设置一些基本运行的参数。然后用parameterize()方法启用ParameterHandler设置参数,完成预编译,执行查询。如果是查询,mybatis会使用ResultSetHandler封装结果返回给调用者。

  - ParameterHandler——参数处理器

    - 它的作用是完成对预编译参数的设置

    - ```java
      public interface ParameterHandler {
          //返回参数对象
          Object getParameterObject();
          //设置预编译sql语句的参数
          void setParameters(PreparedStatement var1) throws SQLException;
      }
      ```

      ```java
      //实现类
      public class DefaultParameterHandler implements ParameterHandler {
          private final TypeHandlerRegistry typeHandlerRegistry;
          private final MappedStatement mappedStatement;
          private final Object parameterObject;
          private final BoundSql boundSql;
          private final Configuration configuration;
      ......
          public void setParameters(PreparedStatement ps) {
              ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());
              List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
              if (parameterMappings != null) {
                  for(int i = 0; i < parameterMappings.size(); ++i) {
                      ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
                      if (parameterMapping.getMode() != ParameterMode.OUT) {
                          String propertyName = parameterMapping.getProperty();
                          Object value;
                          if (this.boundSql.hasAdditionalParameter(propertyName)) {
                              value = this.boundSql.getAdditionalParameter(propertyName);
                          } else if (this.parameterObject == null) {
                              value = null;
                          } else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
                              value = this.parameterObject;
                          } else {
                              MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
                              value = metaObject.getValue(propertyName);
                          }
      
                          TypeHandler typeHandler = parameterMapping.getTypeHandler();
                          JdbcType jdbcType = parameterMapping.getJdbcType();
                          if (value == null && jdbcType == null) {
                              jdbcType = this.configuration.getJdbcTypeForNull();
                          }
      
                          try {
                              typeHandler.setParameter(ps, i + 1, value, jdbcType);
                          } catch (TypeException var10) {
                              throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var10, var10);
                          } catch (SQLException var11) {
                              throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var11, var11);
                          }
                      }
                  }
              }
      
          }
      }
      ```

    - 从paramterObject对象中取到参数,然后使用typeHandler转换参数,如果有设置,那么它会根据签名注册的typeHandler对参数进行处理。而typeHandler也是再mybatis初始化时,注册在Configuration中的

  - ResultSetHandler——结果处理器

    - 用来组装结果返回

    - ```java
      public interface ResultSetHandler {
          //用来包装结果集
          <E> List<E> handleResultSets(Statement var1) throws SQLException;
          <E> Cursor<E> handleCursorResultSets(Statement var1) throws SQLException;
      	//处理存储过程输出参数
          void handleOutputParameters(CallableStatement var1) throws SQLException;
      }
      ```

    - ```java
      public class DefaultResultSetHandler implements ResultSetHandler {  
      	public List<Object> handleResultSets(Statement stmt) throws SQLException {
              ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
              List<Object> multipleResults = new ArrayList();
              int resultSetCount = 0;
              ResultSetWrapper rsw = this.getFirstResultSet(stmt);
              List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
              int resultMapCount = resultMaps.size();
              this.validateResultMapsCount(rsw, resultMapCount);
              while(rsw != null && resultMapCount > resultSetCount) {
                  ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
                  this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
                  rsw = this.getNextResultSet(stmt);
                  this.cleanUpAfterHandlingResultSet();
                  ++resultSetCount;
              }
              String[] resultSets = this.mappedStatement.getResultSets();
              if (resultSets != null) {
                  while(rsw != null && resultSetCount < resultSets.length) {
                      ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
                      if (parentMapping != null) {
                          String nestedResultMapId = parentMapping.getNestedResultMapId();
                          ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
                          this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
                      }
                      rsw = this.getNextResultSet(stmt);
                      this.cleanUpAfterHandlingResultSet();
                      ++resultSetCount;
                  }
              }
              return this.collapseSingleResultList(multipleResults);
          }
      }
      ```

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值