Mybatis源码解析四、SqlSession运行过程

来源:互联网 发布:精索静脉曲张程度数据 编辑:程序博客网 时间:2024/06/05 18:25



 


 一、SqlSession的创建过程
    SqlSessionFactory调用openSession()方法,该方法有很多重载形式,我们以无参方法为例。
    
  1. public SqlSession openSession() {
  2. return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  3. }
    其中ExecutorType是执行器的类型。false表示不自动提交事务,null,表示事务隔离级别,无参表示是数据库的默认隔离级别。

    
  1. private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  2. Transaction tx = null;
  3. try {
  4. final Environment environment = configuration.getEnvironment();
  5. final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
  6. tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
  7. final Executor executor = configuration.newExecutor(tx, execType);
  8. return new DefaultSqlSession(configuration, executor, autoCommit);
  9. } catch (Exception e) {
  10. closeTransaction(tx); // may have fetched a connection so lets call close()
  11. throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
  12. } finally {
  13. ErrorContext.instance().reset();
  14. }
  15. }
从上面代码中我们可以看到,首先会获得我们配置的环境,接着生成事务工厂,根据事务工厂获取数据源,创建事务。
接着创建Executor执行器对象。
    
  1. public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
  2. executorType = executorType == null ? defaultExecutorType : executorType;
  3. executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
  4. Executor executor;
  5. if (ExecutorType.BATCH == executorType) {
  6. executor = new BatchExecutor(this, transaction);
  7. } else if (ExecutorType.REUSE == executorType) {
  8. executor = new ReuseExecutor(this, transaction);
  9. } else {
  10. executor = new SimpleExecutor(this, transaction);
  11. }
  12. if (cacheEnabled) {
  13. executor = new CachingExecutor(executor);
  14. }
  15. executor = (Executor) interceptorChain.pluginAll(executor);
  16. return executor;
  17. }
会根据我们配置执行器创建对应的执行器。可以看到执行器分为三种。
SIMPLE 简易执行器,也即默认执行器。
REUSE 是一种重用预处理语句的执行器。
BATCH 是专门针对批量处理的执行器,提供重用语句以及批量更新。
接着会把执行器加入到插件链中。
二、SqlSession执行过程
   根据之前的博文,我们知道调用Mapper接口中的查询方法,最后都是使用动态代理的方式通过SqlSession中的方法实现的。
所以 我们以sqlSession.selectOne()方法为例看一下SqlSession的执行过程。
跟踪代码我们可以看到实际执行的是SqlSession的selectList()方法。
  1. public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  2. try {
  3. MappedStatement ms = configuration.getMappedStatement(statement);
  4. List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  5. return result;
  6. } catch (Exception e) {
  7. throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
  8. } finally {
  9. ErrorContext.instance().reset();
  10. }
  11. }
其中MapperStatement是解析mapper.xml文件生成的对象,里面存储了我们在mapper.xml文件中的配置。
执行执行器Executor中的query()方法。
  1. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  2. ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  3. if (closed) throw new ExecutorException("Executor was closed.");
  4. if (queryStack == 0 && ms.isFlushCacheRequired()) {
  5. clearLocalCache();
  6. }
  7. List<E> list;
  8. try {
  9. queryStack++;
  10. list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
  11. if (list != null) {
  12. handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
  13. } else {
  14. list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
  15. }
  16. } finally {
  17. queryStack--;
  18. }
  19. if (queryStack == 0) {
  20. for (DeferredLoad deferredLoad : deferredLoads) {
  21. deferredLoad.load();
  22. }
  23. deferredLoads.clear(); // issue #601
  24. if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
  25. clearLocalCache(); // issue #482
  26. }
  27. }
  28. return list;
  29. }

上面可以看到首先会从缓存中进行查找,如果缓存中没有,就会执行queryFromDatabase()方法从数据库中进行查找。
    
  1. private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  2. List<E> list;
  3. localCache.putObject(key, EXECUTION_PLACEHOLDER);
  4. try {
  5. list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  6. } finally {
  7. localCache.removeObject(key);
  8. }
  9. localCache.putObject(key, list);
  10. if (ms.getStatementType() == StatementType.CALLABLE) {
  11. localOutputParameterCache.putObject(key, parameter);
  12. }
  13. return list;
  14. }
接着执行doQuery()方法。
我们以SimpleExecutor中的doQuery()方法为例。
  1. public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  2. Statement stmt = null;
  3. try {
  4. Configuration configuration = ms.getConfiguration();
  5. StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  6. stmt = prepareStatement(handler, ms.getStatementLog());
  7. return handler.<E>query(stmt, resultHandler);
  8. } finally {
  9. closeStatement(stmt);
  10. }
  11. }
从代码中我们可以看到后面主要的操作对象时StatementHandler也即数据库会话器。是用专门用于处理数据库会话的。
先看一下创建StatementHadnler的过程。
  1. public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  2. StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  3. statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  4. return statementHandler;
  5. }
上面的代码和Executor的创建过程类似,创建之后都是添加到插件链中。
    
  1. public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  2. switch (ms.getStatementType()) {
  3. case STATEMENT:
  4. delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  5. break;
  6. case PREPARED:
  7. delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  8. break;
  9. case CALLABLE:
  10. delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  11. break;
  12. default:
  13. throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
  14. }
  15. }
上面我们很清除的看到StatementHandler对象也分为三种,一种是简单的数据库会话器。一种是预处理数据库会话器。最后一种是会有返回参数的数据库绘会话器。和上面提到的三种执行器Executor是一一对应的。
创建好数据库会话器StatementHandler之后,就执行prepareStatement()方法。准备sql以及参数。
  1. private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  2. Statement stmt;
  3. Connection connection = getConnection(statementLog);
  4. stmt = handler.prepare(connection);
  5. handler.parameterize(stmt);
  6. return stmt;
  7. }
其中prepare()方法是用于预处理sql的。paremeterize()方法是用于处理参数的。
  1. public Statement prepare(Connection connection) throws SQLException {
  2. ErrorContext.instance().sql(boundSql.getSql());
  3. Statement statement = null;
  4. try {
  5. statement = instantiateStatement(connection);
  6. setStatementTimeout(statement);
  7. setFetchSize(statement);
  8. return statement;
  9. } catch (SQLException e) {
  10. closeStatement(statement);
  11. throw e;
  12. } catch (Exception e) {
  13. closeStatement(statement);
  14. throw new ExecutorException("Error preparing statement. Cause: " + e, e);
  15. }
  16. }
真正预处理sql的方法是instantiateStatement();这里不再深入探讨,因为其主要涉及到的是一些细节问题。
上述过程处理完后,就会就会执行StatementHadnler的query()方法。
  1. public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  2. PreparedStatement ps = (PreparedStatement) statement;
  3. ps.execute();
  4. return resultSetHandler.<E> handleResultSets(ps);
  5. }
真正执行查询的操作就是ps.execute()方法。
    而resultSetHandler.handleResultSets()方法就是对返回结果集的封装。
0 0
原创粉丝点击