mybatis与spring集成中一级缓存失效的原因

一、缓存失效的原因

首先要明确一个知识点,就是关于一级缓存生效的条件,其中一个条件就是一级缓存只在同一会话中生效,也就是同一个session。明确这一点,也就知道spring中如果不配置事务就会导致一级缓存失效的原因。

spring中使用的sqlsession会话时SqlSessionTemplate,也实现了SqlSession接口。

// session工厂,里面携带了configuration等重要信息
private final SqlSessionFactory sqlSessionFactory;

// 执行器的种类,具体执行数据库操作
private final ExecutorType executorType;

// 是一个session代理类,也是sqlsessionTemplate中实际执行的类
private final SqlSession sqlSessionProxy;

private final PersistenceExceptionTranslator exceptionTranslator;

SqlSessionTemplate中最重要的就是其内部类,SqlSessionInterceptor

private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在代理执行session操作时,会首先去获得一个sqlsession
// 这也就是为什么说spring在不配置事务的情况下会生成不同会话的原因
      SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator
              .translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

进入getSqlSession看看更深入的源码,是否跟上面所说一样呢?

// SqlSessionUtils中产生session的工具方法
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
    notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

// 这里就看到了Transaction,先尝试通过事务去获取会话
    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

    SqlSession session = sessionHolder(executorType, holder);
// 如果获取了会话,就返回该session
    if (session != null) {
      return session;
    }

    LOGGER.debug(() -> "Creating a new SqlSession");
// 否则就新创建一个session
// 所以说会产生不同的会话
    session = sessionFactory.openSession(executorType);

    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

    return session;
  }

 

posted @ 2021-02-22 20:14  4verson  阅读(172)  评论(0)    收藏  举报