Mybatis 中 SqlSession接口的三种实现

发布时间 2024-01-09 19:22:47作者: 长城VIP

Mybatis 中 SqlSession接口的三种实现

SqlSession​ 是一个接口,并且里面包含了许多 CRUD 操作数据库等方法。

SqlSession​​ 它有三个实现类,分别是 SqlSessionManager​​ 、DefaultSqlSession​​ 和 SqlSessionTemplate​​,其中 DefaultSqlSession​​ 它的默认实现类。

DefaultSqlSession 是线程不安全的 Sqlsession 。也就是说 DefaultSqlSession 不能是单例,必须是多例的。

SqlSessionManager​ 和 SqlSessionTemplate​ 是 SqlSession 的代理版,每次新建一个代理对象。姿势都是一样的,但是代理逻辑SqlSessionInterceptor 是不一样的。

代理 DefaultSqlSession 实现复用

在执行 getSqlSession 时,两则都是利用 SessionFactory 工厂创建一个 DefaultSqlSession。然后尽可能复用 DefaultSqlSession,而非多例的每次使用都创建一个 DefaultSqlSession。

SqlSession session = sessionFactory.openSession(executorType);

不同之处在于复用逻辑,先看 SqlSessionTemplate 的:

  1. SqlSessionTemplate ​会将 SqlSession 封装成 SqlSessionHolder,并有利用引用计数法,当 referenceCount>0。表示 SqlSession 还在使用。
  2. 将 sqlSessionHolder 存放到 TransactionSynchronizationManager ​的 synchronizations ​中。synchronizations ​是一个 set 集合。

相对 SqlSessionTemplate 的,SqlSessionManage 的比较简单一点。

  1. SqlSessionManage 内部有一个线程私有变量 localSqlSession。private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal();
  2. SqlSessionManage 会将 DefaultSqlSession 放入到 ThreadLocal 线程私有的变量 localSqlSession 中
  3. 用的时候先从 localSqlSession 中获取 DefaultSqlSession,如果没有获取到则创建。

SqlSessionManager 的代理逻辑

private SqlSessionManager(){
    this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),
    new Class[]{SqlSession.class}, new SqlSessionInterceptor());
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    SqlSession sqlSession = (SqlSession)SqlSessionManager.this.localSqlSession.get();
    if (sqlSession != null) {
       return method.invoke(sqlSession, args);
    } else {
        SqlSession autoSqlSession = SqlSessionManager.this.openSession();
        Object var8;
        try {
            try {
                Object result = method.invoke(autoSqlSession, args);
                autoSqlSession.commit();
                var8 = result;
            } catch (Throwable var20) {
                autoSqlSession.rollback();
                throw ExceptionUtil.unwrapThrowable(var20);
            }
        } catch (Throwable var21) {

        } finally {
            if (autoSqlSession != null) {
                autoSqlSession.close(); 
            }
        }

        return var8;
    }
}

SqlSessionTemplate 的代理逻辑

private SqlSessionTemplate(){
    this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), 
    new Class[]{SqlSession.class}, new SqlSessionInterceptor());
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    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;
}