1. 程式人生 > >ssm框架-快取淺談

ssm框架-快取淺談

快取的概念

        java裡快取可以分兩種情況,一種是JVM的快取,這個是JVM與作業系統打交道用的,在使用java語言開發時,一般不用到。

        一種是java語言快取,這裡的快取是一種機制,不與任何硬體相關。比如一個 static的變數, 當第一次訪問他時我們到檔案裡讀他的值,以後訪問時,直接把這個值返回去,這裡省下了IO的時間,提高了效率,這就是一個簡單的快取機制。

一級快取

        一級快取是SqlSession級別的快取。在操作資料庫時需要構造sqlSession物件,在物件中有一個數據結構用於儲存快取資料。不同的sqlSession之間的快取資料區域是互相不影響的。也就是他只能作用在同一個sqlSession中,不同的sqlSession中的快取是互相不能讀取的。

處理流程:

        使用者發起查詢請求,查詢某條資料,sqlSession先去快取中查詢,是否有該資料,如果有,讀取;

        如果沒有,從資料庫中查詢,並將查詢到的資料放入一級快取區域,供下次查詢使用。

        但sqlSession執行commit,即增刪改操作時會清空快取。這麼做的目的是避免髒讀。

        如果commit不清空快取,會有以下場景:A查詢了某商品庫存為10件,並將10件庫存的資料存入快取中,之後被客戶買走了10件,資料被delete了,但是下次查詢這件商品時,並不從資料庫中查詢,而是從快取中查詢,就會出現錯誤。

二級快取

        二級快取是mapper級別的快取,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級快取,二級快取是跨SqlSession的。

        UserMapper有一個二級快取區域(按namespace分),其它mapper也有自己的二級快取區域(按namespace分)。每一個namespace的mapper都有一個二級快取區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢到資料將存在相同的二級快取區域中。

處理流程:




這裡有一個問題,既然有了一級快取,那麼為什麼要提供二級快取呢?

        二級快取是mapper級別的快取,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級快取,二級快取是跨SqlSession的。二級快取的作用範圍更大。

        還有一個原因,實際開發中,MyBatis通常和Spring進行整合開發。Spring將事務放到Service中管理,對於每一個service中的sqlsession是不同的,這是通過mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer建立sqlsession自動注入到service中的。 每次查詢之後都要進行關閉sqlSession,關閉之後資料被清空。所以spring整合之後,如果沒有事務,一級快取是沒有意義的。

二級快取的使用:

1,開啟總開關

在MyBatis的配置檔案中加入:

<settings>    

   <!--開啟二級快取-->    

    <setting name="cacheEnabled" value="true"/>    

</settings>

2,在需要開啟二級快取的mapper.xml中加入caceh標籤

<cache/>

3,讓使用二級快取的POJO類實現Serializable介面

public class User implements Serializable {}

整合ehcache

        分散式快取能夠高效能地讀取資料、能夠動態地擴充套件快取節點、能夠自動發現和切換故障節點、能夠自動均衡資料分割槽,而且能夠為使用者提供圖形化的管理介面,部署和維護都十分方便。

        而mybatis無法實現分散式快取,需要和其它分散式快取框架進行整合。這裡簡單介紹和ehcache整合。

整合流程:

        mybatis提供了一個cache介面,如果要實現自己的快取邏輯,實現cache介面開發即可。

        mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個cache介面的實現類。

package org.apache.ibatis.cache.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
/**
 * @author Yien
 */
public class PerpetualCache implements Cache {  
    private String id;  
    private Map<Object, Object> cache = new HashMap<Object, Object>();  
    public PerpetualCache(String id) {    
        this.id = id;
    }  
    public String getId() {    
        return id;
    } 
    public int getSize() {    
        return cache.size();
    }  
    public void putObject(Object key, Object value) {
        cache.put(key, value);
    }  
    public Object getObject(Object key) {    
        return cache.get(key);
    } 
    public Object removeObject(Object key) {   
        return cache.remove(key);
    }  
    public void clear() {
        cache.clear();
    }  
    public ReadWriteLock getReadWriteLock() {    
        return null;
    }  
    public boolean equals(Object o) {    
       if (getId() == null) throw new CacheException("Cache instances require an ID.");    
       if (this == o) 
          return true;    
       if (!(o instanceof Cache)) 
          return false;
       Cache otherCache = (Cache) o;    
       return getId().equals(otherCache.getId());
    }  
   public int hashCode() {    
       if (getId() == null) throw new CacheException("Cache instances require an ID.");    
           return getId().hashCode();
   }
}


配置步驟:

1,配置mapper中cache中的type為ehcache對cache介面的實現型別

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

        表示開啟此mapper的namespace下的二級快取  

type表示指定cache介面的實現類的型別,mybatis預設使用PerpetualCache。

要和ehcache整合,需要配置type為ehcache實現cache介面的型別。

2,加入ehcache的配置檔案

        在classpath下配置ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <diskStore path="F:\develop\ehcache" />
    <defaultCache 
        maxElementsInMemory="1000" 
        maxElementsOnDisk="10000000"
        eternal="false" 
        overflowToDisk="false" 
        timeToIdleSeconds="120"
        timeToLiveSeconds="120" 
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
    </defaultCache></ehcache>


3,Maven中ehcache 相關依賴

<dependency>
     <groupId>org.ehcache</groupId>
     <artifactId>ehcache</artifactId>
     <version>3.1.3</version>
     </dependency>
 <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-ehcache -->
 <dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis-ehcache</artifactId>
     <version>1.0.0</version>
</dependency>


最後,簡單比較三個比較流行的快取工具。

        ehcache 是一個純Java的程序內快取框架,hibernate使用其做二級快取。同時,ehcache可以通過多播的方式實現叢集。

        memcache是一套分散式的快取記憶體系統,提供key-value這樣簡單的資料儲存,可充分利用CPU多核,無持久化功能。

        redis高效能的key-value系統,提供豐富的資料型別,單核CPU有抗併發能力,有持久化和主從複製的功能。