美文网首页
SqlSession到底是怎么处理我们的数据操作请求的?

SqlSession到底是怎么处理我们的数据操作请求的?

作者: 晨暮时代 | 来源:发表于2019-05-15 11:13 被阅读0次

    主旨

    当我们使用SqlSession调用数据库操作语句的时候,其内部处理流程是怎样的,类与类之间关系如何。

    分析

    在我们的springboot项目中,加入mybatis的使用是件容易的事情,如果没有特别深入的要求,只需在application.yml中添加极少的配置,便可直接在代码中通过注入SqlSession调用我们写在mapper文件中的sql。那么,当我们调用SqlSession中的selectList或selectOne方法时,mybatis究竟为我们做了些什么呢?

    首先我们要知道,Mybatis通过自动配置的方式为我们减少了很多操作,我们需要找到一个关键类——MybatisAutoConfiguration。它位于mybatis-springboot-autoconfigure包下。把我们的目光放在SqlSessionTemplate这个方法上,点进去,发现它实现了SqlSession。

    
    public class SqlSessionTemplate implements SqlSession, DisposableBean {
    
        private final SqlSessionFactory sqlSessionFactory;
    
        private final ExecutorType executorType;
    
        private final SqlSession sqlSessionProxy;
    
        private final PersistenceExceptionTranslator exceptionTranslator;
    
        public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    
            this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
    
        }
    
        public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
    
            this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
    
        }
    
        public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    
            Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    
            Assert.notNull(executorType, "Property 'executorType' is required");
    
            this.sqlSessionFactory = sqlSessionFactory;
    
            this.executorType = executorType;
    
            this.exceptionTranslator = exceptionTranslator;
    
            this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
    
        }
    
    

    注意sqlSessionProxy 这个变量,它采用了JDK动态代理,生成代理对象的第三个参数为其私有内部类SqlSessionInterceptor,这个类尤其重要,稍后会重新提及。

    一般在我们使用时,会直接在Dao层添加SqlSession的引入,然后通过控制器自动注入:

    
    public UserDao(SqlSession sqlSession) {
    
    this.sqlSession = sqlSession;
    
    }
    
    public List<User> findList(Map<String, Object> condition) {
    
    return this.sqlSession.selectList("findList", condition);
    
    }
    
    

    这里的sqlSession变量的实例类为SqlSessionTemplate。

    当一个请求过来的时候,比如调用selectList方法,会被引入到SqlSessionTemplate的selectList方法下,这时我们注意到,它又调用了sqlSessionProxy的同名方法:

    
    public <E> List<E> selectList(String statement) {
    
        return this.sqlSessionProxy.selectList(statement);
    
    }
    
    

    注意了!!!

    随后请求会进入到SqlSessionInterceptor类的invoke方法下:

    
    private class SqlSessionInterceptor implements InvocationHandler {
    
            private SqlSessionInterceptor() {
    
            }
    
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //重新获取一个sqlSession,它跟我们在Dao层中看的sqlSession并非同一个实例
                SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
    
                Object unwrapped;
    
                try {
    
                    Object result = method.invoke(sqlSession, args);
    
                    if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
    
                        sqlSession.commit(true);
    
                    }
    
                    unwrapped = result;
    
                } catch (Throwable var11) {
    
                    unwrapped = ExceptionUtil.unwrapThrowable(var11);
    
                    if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
    
                        SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
    
                        sqlSession = null;
    
                        Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
    
                        if (translated != null) {
    
                            unwrapped = translated;
    
                        }
    
                    }
    
                    throw (Throwable)unwrapped;
    
                } finally {
    
                    if (sqlSession != null) {
    
                        SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
    
                    }
    
                }
    
                return unwrapped;
    
            }
    
        }
    
    

    看到invoke方法下又出现了一个sqlsession没有?它跟我们在Dao层看到的那个sqlSession可不一样。点进getSqlSession这个方法:

    public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    
            Assert.notNull(sessionFactory, "No SqlSessionFactory specified");
    
            Assert.notNull(executorType, "No ExecutorType specified");
    
            SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
    
            SqlSession session = sessionHolder(executorType, holder);
    
            if (session != null) {
    
                return session;
    
            } else {
    
                if (LOGGER.isDebugEnabled()) {
    
                    LOGGER.debug("Creating a new SqlSession");
    
                }
                // 重新获取一个sqlSession实例
                session = sessionFactory.openSession(executorType);
    
                registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
    
                return session;
    
            }
    
        }
    
    

    可以看到它是重新从SqlSessionFactory获取的SqlSession实例,要想知道这个实例类是什么,需要点进openSession这个方法。或许你会疑问,SqlSessionFactory有两个实例类,分别是DefaultSqlSessionFactory和SqlSessionManager,该选择哪个?这里,我们使用的是DefaultSqlSessionFactory,因此你需要查看DefaultSqlSessionFactory里的openSession方法,如下:

        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);
                // invoke里sqlSession的实例类
                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;
    
        }
    
    

    OK,现在我们知道了invoke方法里的sqlSession的实例类是DefaultSqlSession,然后回过头去继续看invoke方法。当执行Object result = method.invoke(sqlSession, args);时,最终会执行到DefaultSqlSession下的同名selectList方法,即:

    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    
        List var5;
    
        try {
    
            MappedStatement ms = this.configuration.getMappedStatement(statement);
    
            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;
    
    }
    
    

    相关文章

      网友评论

          本文标题:SqlSession到底是怎么处理我们的数据操作请求的?

          本文链接:https://www.haomeiwen.com/subject/xjouaqtx.html