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有抗併發能力,有持久化和主從複製的功能。