mybatis源碼解析(一)-開篇
mybatis源碼解析(二)-加載過程
mybatis源碼解析(三)-SqlSession.selectOne類似方法調用過程
mybatis源碼解析(四)-Mapper方法調用過程
mybatis源碼解析(五)-mybatis如何實作的事務控制
mybatis源碼解析(六)-配合spring-tx實作事務的原理
mybatis源碼解析(七)-當mybatis一級緩存遇上spring
轉載請标明出處:
https://blog.csdn.net/bingospunky/article/details/79713284
本文出自馬彬彬的部落格
mybatis一級緩存
mybatis一級緩存的作用範圍是SqlSession,可以通過SqlSession的getMapper方法建立Mapper,可以通過是否是一個SqlSession來控制一級緩存的作用域。
當mybatis一級緩存遇上spring
考慮這樣的情況:controlle、service、mapper都是使用spring容器管理的,在spring容器中,這些bean都是單例的。由于mapper是單例,mapper中的SqlSession如果是同一個,那麼一級緩存就會生效。如果我們執行了一次查詢,且查詢結果已經被一級緩存了,這時候我們修改資料庫裡的内容,再去執行這個查詢的時候,查詢緩存在一級緩存裡的内容,這顯然是不可取的。事實是:當使用mybatis配合spring使用時,每次使用mapper查詢都是新的結果,不會使用一級緩存。那麼這是怎麼做到的呢?
Mapper中有一個屬性叫sqlSession,該屬性是SqlSessionTemplate類型的,當需要執行sql時,Mapper會調用這個SqlSessionTemplate對象去執行。
SqlSessionTemplate裡有一個屬性叫sqlSessionProxy,這個屬性是個jdbc代理對象,當SqlSessionTemplate需要去執行sql時,會調用這個jdbc代理去執行的。我們來看下這個jdbc代理的實作:
Code1
org.mybatis.spring.SqlSessionTemplate.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;
}
}
Code1第5行,這個jdbc代理方法被調用時,每次都會建立新的SqlSession對象,這樣就可以使一級緩存失效。
下面是這個jdbc代理對象的建立過程:
Code2
org.mybatis.spring.SqlSessionTemplate
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());
}
Code2第7行,是這個jdbc代理對象的建立過程,可以看到這個代理過程,沒有被代理的對象,應該就是專門為了在配合spring時,實作每次調用SqlSession方法時都産生新的SqlSession吧。