天天看點

Mybatis強制查詢問題

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。

每天努力一點,每天都在進步。