当我们单独使用MyBatis的时候,一级缓存在一个会话中存在。当SqlSession对象打开就已经存在,当SqlSession对象关闭时缓存数据被清空
当与Spring整合的时候。Spring对MyBatis中SqlSession的使用是通过SqlSessionTemplate来控制的。SqlSessionTemplate作为Bean存放在IOC容器中。Spring通过MyBatis操作数据库的过程如下
所以,可以发现在Spring中重复查询数据使用的SqlSession是不同的。通过研究源码
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());
}
在SqlSessionTemplate的构造函数中,通过JDK动态代理的方式生成SqlSession.主体逻辑存在于内部类SqlSessionInterceptor中
private class SqlSessionInterceptor implements InvocationHandler {
private 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;
}
}
在invoke方法中我们可以看到每次对sqlSession进行了create、commit、close。
因为每次都需要进行创建,所以导致了一级缓存的失效。
但是,当我们开启了事务之后,一级缓存又会生效。跟进到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 {
LOGGER.debug(() -> {
return "Creating a new SqlSession";
});
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
}
我们可以发现SqlSession对象是通过sessionHolder获取的。此时,若是事务存在,我们可以获取到SqlSession对象,就不需要再次创建SqlSession对象了。SqlSession没有经过销毁再创建的过程,一级缓存自然就不会失效了。