Mybatis強制查詢緩存問題
1、對于經常用Mybatis架構的開發人員來說,都知道Mybatis進行資料庫查詢時的一個特性:
Mybatis連續執行兩次相同的查詢,Mybatis是不會去資料庫中查詢,而是直接從sqlsession中取,傳回的對象也是同一個對象。簡單來說就是不會再發出sql查詢而是使用緩存的資料。這對于經常使用查詢的系統無疑是一個非常好的特性,對于大量資料查詢來說就是節約大量資源,降低開發成本。
但是我們有時候有特殊需要,那些資料一定要進行查詢再能得到的,否則就會得到資料不一緻的情況,這時候我們如何處理?
2、解決方案:
若是想要每次查詢都傳回新的對象,隻需在xml檔案select标簽裡添加屬性 flushCache="true"。
3、MyBatis的緩存機制(分為一級緩存和二級緩存)
3.1一級緩存:
MyBatis的一級緩存指的是在一個Session域内,session為關閉的時候執行的查詢會根據SQL為key,資料為value被緩存。
1)單獨使用MyBatis而不繼承Spring,使用原生的MyBatis的SqlSessionFactory來構造sqlSession查詢,是可以使用以及緩存的,示例代碼如下
public class Test {
public static void main(String[] args) throws IOException {
String config = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(config);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
System.out.println(session.selectOne("selectUserByID", 1));
// 同一個session的相同sql查詢,将會使用一級緩存
System.out.println(session.selectOne("selectUserByID", 1));
// 參數改變,需要重新查詢
System.out.println(session.selectOne("selectUserByID", 2));
// 清空緩存後需要重新查詢
session.clearCache();
System.out.println(session.selectOne("selectUserByID", 1));
// session close以後,仍然使用同一個db connection
session.close();
session = factory.openSession();
System.out.println(session.selectOne("selectUserByID", 1));
}
}
當參數不變的時候隻進行了一次查詢,參數變更以後,則需要重新進行查詢,而清空緩存以後,參數相同的查詢過的SQL也需要重新查詢。
2) 和Spring內建的時候
@Repository
public class UserDao extends SqlSessionDaoSupport {
public User selectUserById(int id) {
SqlSession session = getSqlSession();
session.selectOne("dao.userdao.selectUserByID", id);
// 由于session的實作是SqlSessionTemplate的動态代理實作
// 它已經在代理類内執行了session.close(),是以無需手動關閉session
return session.selectOne("dao.userdao.selectUserByID", id);
}
}
這裡執行了2次sql查詢,看似我們使用了同一個sqlSession,但是實際上因為我們的dao繼承了SqlSessionDaoSupport,而SqlSessionDaoSupport内部sqlSession的實作是使用用動态代理實作的,這個動态代理sqlSessionProxy使用一個模闆方法封裝了select()等操作,每一次select()查詢都會自動先執行openSession(),執行完close()以後調用close()方法,相當于生成了一個新的session執行個體,是以 我們無需手動的去關閉這個session(),當然也無法使用mybatis的一級緩存,也就是說mybatis的一級緩存在spring中是沒有作用的。
3.2二級緩存
二級緩存就是global caching,它超出session範圍之外,可以被所有sqlSession共享,它的實作機制和mysql的緩存一樣,開啟它隻需要在mybatis的配置檔案開啟settings裡的。
<setting name="cacheEnabled" value="true"/>
以及在相應的Mapper檔案裡開啟。
<mapper namespace="dao.userdao">
... select statement ...
<!-- Cache 配置 -->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true" />
</mapper>
需要注意的是global caching的作用域是針對Mapper的Namespace而言的,也就是說隻在有在這個Namespace内的查詢才能共享這個cache。
每天努力一點,每天都在進步。