一起学习Mybatis----mybatis的运行原理

版权声明:本文为博主原创文章,转载请说明出处。 https://blog.csdn.net/weixin_43549578/article/details/84883307

mybatis的生命周期包含4部分:

         1. SqlSessionFactoryBuilder

          2.SqlSessionFactory

          3.SqlSession

          4.Mapper

      mybatis的运行是先根据相关的配置文件通过SqlSessionFactoryBuilder构建SqlSessionFactory,在根据SqlSessionFactory去创建响应的SqlSession,SqlSession在根据Mapper传递的sql,进行相关的动作,返回结构给Mapper.

构建SqlSessionFactory过程:

    第一步:
         通过 org.apache. ibatis. builder.xmL.XMLConfigBuilder解析配置的XML文件,读出配置参数,并将读取的数据存入这个org.apache ibatis session. Configuration类中。注意MyBatis几乎所有的配置都是存在这里的。
    第二步:
         使用 Confinguration对象去创建 SqlSession Factory。 My Batis中的 SqlSession Factory是一个接口,而不是实现类,为此 My Batis提供了一个默认的 Sqlsession Factory实现类,我们般都会使用它 org.apache ibatis session. defaults. Defaultsqlsession Factory。注意,在大部分情况下我们都没有必要自己去创建新的 Sqlsession Factory的实现类。

Configuration 源码:

public class Configuration {
    protected Environment environment;
    protected boolean safeRowBoundsEnabled;
    protected boolean safeResultHandlerEnabled;
    protected boolean mapUnderscoreToCamelCase;
    protected boolean aggressiveLazyLoading;
    protected boolean multipleResultSetsEnabled;
    protected boolean useGeneratedKeys;
    protected boolean useColumnLabel;
    protected boolean cacheEnabled;
    protected boolean callSettersOnNulls;
    protected boolean useActualParamName;
    protected boolean returnInstanceForEmptyRow;
    protected String logPrefix;
    protected Class<? extends Log> logImpl;
    protected Class<? extends VFS> vfsImpl;
    protected LocalCacheScope localCacheScope;
    protected JdbcType jdbcTypeForNull;
    protected Set<String> lazyLoadTriggerMethods;
    protected Integer defaultStatementTimeout;
    protected Integer defaultFetchSize;
    protected ExecutorType defaultExecutorType;
    protected AutoMappingBehavior autoMappingBehavior;
    protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
    protected Properties variables;
    protected ReflectorFactory reflectorFactory;
    protected ObjectFactory objectFactory;
    protected ObjectWrapperFactory objectWrapperFactory;
    protected boolean lazyLoadingEnabled;
    protected ProxyFactory proxyFactory;
。。。。。。

   Configuration作用:

     1. 读入配置文件,包括基础配置的XML文件和映射器的XML文件。
     2.初始化基础配置,比如 My Batis的别名等,一些重要的类对象,例如,插件、映射器、 ObjectFactory和 type Handler对象
     3.提供单例,为后续创建 SessionFactory服务并提供配置的参数执行一些重要的对象方法,初始化配置信息。

   在第一步中Mybatis会读取所有的xml文件,将其初始化保存到 Configuration类的单例对象中,初始化包含了:properties全局参数settings设置typeAliases别名typeHandler类型处理器ObjectFactory对象plugin插件,environment环境,DatabaseldProvider数据库标识Mapper映射器。 

     

  sqlSessionFactory=new SqlSessionFactoryBuilder(). build(inputstream).

 org.apache.ibatis.session.SqlSessionFactoryBuilder中的builder方法。

  
 MyBatis会根据 Configuration的配置读取所配置的信息,构建 SqlsessionFactory对象。

SqLSession运行过程:

  探究其原理的了解一下 Mapper映射原理。

 Mapper映射器:构建需要执行的Sql脚本。由三部分组成:

      1. MappedStatement,它保存映射器的一个节点( select|insert|delete|update)。包括许多我们配置的SQL、SQL的id、缓存信息、 resultMap、 parameterType、 resultType、languageDriver等重要配置内容。
      2.SqLSource,它是提供 BoundS对象的地方,它是 MappedStatement的一个属性。
      3. BoundSql,它是建立SQL和参数的地方。它有3个常用的属性:SQL、 parameterObject ,parameterMappings。

 Mapper映射是通过动态代理实现的。

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.binding;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.ibatis.session.SqlSession;

/**
 * @author Lasse Voss
 */
public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
   //动态代理对Mapper接口实行了代理模式,而代理的方法都放置到了MapperProxy类中了
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}
package org.apache.ibatis.binding;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;

import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.SqlSession;

/**
  动态代理模式
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //判断它是否是一个类,显然这里 Mapper是一个接口不是类,所以判定失败
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

}

   上面运用了 invoke方法。一旦 mapper是一个代理对象,那么它就会运行到 invoke方法里面, invoke首先判断它是否是一个类,显然这里 Mapper是一个接口不是类,所以判定失败。那么就会生成 MapperMethod对象,它是通过 cachedMapperMethod方法对其初始化的,然后执行 execute方法,把 sqlsession和当前运行的参数传递进去。

      Mapper执行的过程是通过 Executor、 StatementHandler、Parameter Handler和 Resulthandler来完成数据库操作和结果返回的。

       Executor代表执行器,由它来调度 Statementhandler、 ParameterHandler、 Resulthandler等来执行对应的SQL。

      StatementHandler的作用是使用数据库的 Statement( PreparedStatement)执行操作,它是四大对象的核心,起到承上启下的作用。

     ParameterHandler用于SQL对参数的处理。

    Resulthandler是进行最后数据集( Resultset)的封装返回处理的。

Executor执行器:创建执行器首先根据Configuration获取执行器类型。

 在创建sqlSession就开始初始化:

生成指定的执行器。

public class SimpleExecutor extends BaseExecutor {

  。。。。。。。。。。。。。。。。。。。。。。。。。。。。

  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

 。。。。。。。。。。。。。。。。。。。。。。。。。。

}

    显然 MyBatis根据 Configuration来构建 Statementhandler,然后使用 prepareStatement方法,对SQL编译并对参数进行初始化,我们在看它的实现过程,它调用了 Statementhandler的prepare()进行了预编译和基础设置,然后通过 StatementHandler的 parameterize()来设置参数并执行, resulthandler再组装査询结果返回给调用者来完成一次查询。

数据库会话器 StatementHandler:专门处理数据库会话的。

创建会话器:

 

   RoutingStatementHandler不是我们真实的服务对象,它是通过适配模式找到对应的StatementHandler来执行的。在MyBatis中, StatementHandler和 Executor一样分为三种SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler它所对应的是三种执行器。

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

我们最常用的是PreparedStatementHandler:

 预编译

预编译完成就需要开始设置参数。

ParameterHandler:

 设置完参数就需要开始查询了,进行结构封装。

Resulthandler:

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.resultset;

import org.apache.ibatis.cursor.Cursor;

import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
 * @author Clinton Begin
 */
public interface ResultSetHandler {

  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

实现:

结果封装返回。

SqlSession运行原理图:

猜你喜欢

转载自blog.csdn.net/weixin_43549578/article/details/84883307
今日推荐