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

2019-05-15  本文已影响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;

}

上一篇 下一篇

猜你喜欢

热点阅读