Mybatis原理

在Mybatis框架中,当我们需要对数据库进行操作时,主要分为四步,同时也涉及到了四大对象(executor 执行器对象、StatementHandler 预编译处理对象、ParameterHandler 参数处理对象、ResultSetHandler 结果集处理对象),下面我们具体说明一下这四步以及各部分涉及的东西。

第一步,需要通过读取Mybartis配置文件中的信息,通过加载流的形式,来获取SqlSessionFactory这个工厂对象

 //创建sqlSessionFactory
    private static SqlSessionFactory sqlSessionFactory = null;
    static {
        String config = "mybatis.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream (config);
             sqlSessionFactory = new SqlSessionFactoryBuilder ().build (inputStream);
        } catch (IOException e) {
            e.printStackTrace ();
        }
    }


总结:把配置文件的信息解析并保存在Configuration对象中,返回包含了Configuration并且实现了SqlSessionFactory的DefaultSqlSessionFactory对象。

第二步,获取完工厂对象后,我们应该要从SqlSessionFactory这个工厂中获取我们需要的对象即SqlSession

 //获取sqlSession对象
    public static SqlSession getSqlSession()
    {
        SqlSession sqlSession = null;
        if(sqlSessionFactory != null)
        {
            sqlSession = sqlSessionFactory.openSession ();
            return sqlSession;
        }
        return null;
    }

其中SqlSessionFactory中定义了通过openSession()方法,而SqlSessionFactory的实现类为DefaultSqlSessionFactory,
他里面定义了一个Configuration对象属性这个属性在创建 SqlSessionFactory时就将数据库的全局配置信息都包含在内。
在调用DefaultFactory中的openSession()方法时,又调用了openSessionFromDataSource方法来获得数据源并进行一些事务操作的处理,同时也生成了executor这个执行器对象

openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
我们再进入newExecutor方法
 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor 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 (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
可以发现 默认的执行器类型是ExecutorType.SIMPLE,并且在创建执行器的方法中还会判断是否存在二级缓存的配置,
如果存在则通过new CachingExecutor创建二级缓存 ,然后会通过拦截器将executor包装并返回

总结:返回SqlSession的实现类DefaultSqlSession对象,他里面包含了Executor和Configuration,Executor会在这一步被创建

第三步,获取到SqlSession对象后,通过映射获得Dao的代理对象

 StudentDao studentDao = sqlSession.getMapper (StudentDao.class);

其中调用了getMapper方法
@Override
  public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
  }
我们通过查看,仍然发现他是通过配置对象中的getMapper方法返回了一个泛型类对象
mapperRegistry.getMapper(type, sqlSession);
又调用了mapperRegistory的方法
 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
此方法中使用了  MapperProxyFactory获取工厂的对象,并且通过工厂传入sqlSession获取到了一个实例 而这个实例就是代理对象,getMapper返回接口的代理对象包含了SqlSession对象

第四步,查询流程
在上一步创建代理对象的途中,底层也通过反射调用了代理对象的方法,具体流程如下

posted @ 2021-11-22 09:37  苏澜  阅读(38)  评论(0)    收藏  举报