spring+ mybatis 二級快取使用 redis作為快取
springMybatisConfig.xml配置
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" default-autowire="byName" default-lazy-init="false"> <!-- 一、使用druid資料庫連線池註冊資料來源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <!-- 基礎配置 --> <property name="url" value="${jdbc.url}"></property> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="username" value="root"></property> <property name="password" value="password"></property> <!-- 關鍵配置 --> <!-- 初始化時建立物理連線的個數。初始化發生在顯示呼叫init方法,或者第一次getConnection時 --> <property name="initialSize" value="3" /> <!-- 最小連線池數量 --> <property name="minIdle" value="2" /> <!-- 最大連線池數量 --> <property name="maxActive" value="15" /> <!-- 配置獲取連線等待超時的時間 --> <property name="maxWait" value="10000" /> <!-- 效能配置 --> <!-- 開啟PSCache,並且指定每個連線上PSCache的大小 --> <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> <!-- 其他配置 --> <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- 配置一個連線在池中最小生存的時間,單位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000" /> <!-- 建議配置為true,不影響效能,並且保證安全性。申請連線的時候檢測,如果空閒時間大於timeBetweenEvictionRunsMillis, 執行validationQuery檢測連線是否有效。 --> <property name="testWhileIdle" value="true" /> <!-- 這裡建議配置為TRUE,防止取到的連線不可用 ,申請連線時執行validationQuery檢測連線是否有效,做了這個配置會降低效能。--> <property name="testOnBorrow" value="true" /> <!-- 歸還連線時執行validationQuery檢測連線是否有效,做了這個配置會降低效能 --> <property name="testOnReturn" value="false" /> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--dataSource屬性指定要用到的連線池--> <property name="dataSource" ref="dataSource" /> <!-- 開啟快取支援 --> <property name="configurationProperties"> <props> <!--全域性對映器啟用快取--> <prop key="cacheEnabled">true</prop> <!-- 查詢時,關閉關聯物件即時載入以提高效能 --> <prop key="lazyLoadingEnabled">false</prop> <!-- 設定關聯物件載入的形態,此處為按需載入欄位(載入欄位由SQL指定),不會載入關聯表的所有欄位,以提高效能 --> <prop key="aggressiveLazyLoading">true</prop> <!-- 對於未知的SQL查詢,允許返回不同的結果集以達到通用的效果 --> <prop key="multipleResultSetsEnabled">true</prop> <!-- 允許使用列標籤代替列名 --> <prop key="useColumnLabel">true</prop> <!-- 允許使用自定義的主鍵值(比如由程式生成的UUID 32位編碼作為鍵值),資料表的PK生成策略將被覆蓋 --> <prop key="useGeneratedKeys">true</prop> <!-- 給予被巢狀的resultMap以欄位-屬性的對映支援 --> <prop key="autoMappingBehavior">FULL</prop> <!-- 對於批量更新操作快取SQL以提高效能 --> <prop key="defaultExecutorType">BATCH</prop> <!-- 資料庫超過25000秒仍未響應則超時 --> <prop key="defaultStatementTimeout">25000</prop> </props> </property> <!-- 自動掃描mapping.xml檔案 --> <property name="mapperLocations" value="classpath:com/dg/mapping/*.xml"></property> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
springRedisConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd" > <!-- redis資料來源 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大空閒數 --> <property name="maxIdle" value="400" /> <!-- 最大空連線數 --> <property name="maxTotal" value="6000" /> <!-- 最大等待時間 --> <property name="maxWaitMillis" value="1000" /> <!-- 連線超時時是否阻塞,false時報異常,ture阻塞直到超時, 預設true --> <property name="blockWhenExhausted" value="true" /> <!-- 返回連線時,檢測連線是否成功 --> <property name="testOnBorrow" value="true" /> </bean> <!-- Spring-redis連線池管理工廠 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!-- IP地址 --> <property name="hostName" value="127.0.0.1" /> <!-- 埠號 --> <property name="port" value="6379" /> <!-- 超時時間 預設2000 --> <property name="timeout" value="30000" /> <!-- 連線池配置引用 --> <property name="poolConfig" ref="poolConfig" /> <!-- usePool:是否使用連線池 --> <property name="usePool" value="true" /> </bean> <!-- redis template definition --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> <!--開啟事務 --> <property name="enableTransactionSupport" value="true"></property> </bean> <!-- 已下不是實現mybatis的快取介面 實現spring caches介面的快取配置 --> <!--使用實現spring caches的快取方案 快取管理器--> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <!--自定義的redis快取操作實現--> <bean class="com.redisCache.RedisCache"> <property name="name" value="myCache"/> <property name="redisTemplate" ref="redisTemplate"/> </bean> </set> </property> </bean> <!--spring 啟用快取註解--> <cache:annotation-driven cache-manager="cacheManager" /> </beans>
通大多數ORM層框架一樣,Mybatis自然也提供了對一級快取和二級快取的支援。一下是一級快取和二級快取的作用於和定義。
1、一級快取是SqlSession級別的快取。在操作資料庫時需要構造 sqlSession物件,在物件中有一個(記憶體區域)資料結構(HashMap)用於儲存快取資料。不同的sqlSession之間的快取資料區域(HashMap)是互相不影響的。
二級快取是mapper級別的快取,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession去操作資料庫得到資料會存在二級快取區域,多個SqlSession可以共用二級快取,二級快取是跨SqlSession的。
2、一級快取的作用域是同一個SqlSession,在同一個sqlSession中兩次執行相同的sql語句,第一次執行完畢會將資料庫中查詢的資料寫到快取(記憶體),第二次會從快取中獲取資料將不再從資料庫查詢,從而提高查詢效率。當一個sqlSession結束後該sqlSession中的一級快取也就不存在了。Mybatis預設開啟一級快取。
二級快取是多個SqlSession共享的,其作用域是mapper的同一個namespace,不同的sqlSession兩次執行相同namespace下的sql語句且向sql中傳遞引數也相同即最終執行相同的sql語句,第一次執行完畢會將資料庫中查詢的資料寫到快取(記憶體),第二次會從快取中獲取資料將不再從資料庫查詢,從而提高查詢效率。Mybatis預設沒有開啟二級快取需要在setting全域性引數中配置開啟二級快取。
一般的我們將Mybatis和Spring整合時,mybatis-spring包會自動分裝sqlSession,而Spring通過動態代理sqlSessionProxy使用一個模板方法封裝了select()等操作,每一次select()查詢都會自動先執行openSession(),執行完close()以後呼叫close()方法,相當於生成了一個新的session例項,所以我們無需手動的去關閉這個session(),當然也無法使用mybatis的一級快取,也就是說mybatis的一級快取在spring中是沒有作用的。
因此我們一般在專案中實現Mybatis的二級快取,雖然Mybatis自帶二級快取功能,但是如果實在叢集環境下,使用自帶的二級快取只是針對單個的節點,所以我們採用分散式的二級快取功能。一般的快取NoSql資料庫如redis,Mancache等,或者EhCache都可以實現,從而更好地服務tomcat叢集中ORM的查詢。
下面主要通過Redis實現Mybatis的二級快取功能。
1、配置檔案中開啟二級快取
[html] view plain copy
- <setting name="cacheEnabled" value="true"/>
2、實現Mybatis的Cache介面
package com.redisCache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
public class RedisCache implements Cache {
private static Logger logger = LoggerFactory.getLogger(RedisCache1.class);
/** The ReadWriteLock. */
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public final long liveTime = 86400;
private final String COMMON_CACHE_KEY = "COM:";
private String id;
private RedisTemplate<String, Object> redisTemplate;
private ApplicationContext context;
public RedisCache() {
}
public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("必須傳入ID");
}
//springBean 獲取配置好的 RedisTemplate
context = new ClassPathXmlApplicationContext("spring-redis.xml");
redisTemplate =(RedisTemplate)context.getBean("redisTemplate");
logger.debug(">>>>>>>>>>>>>>>>>>>>>MybatisRedisCache:id=" + id);
this.id = id;
}
private String getKey(Object key) {
StringBuilder accum = new StringBuilder();
accum.append(COMMON_CACHE_KEY);
accum.append(this.id).append(":");
accum.append(DigestUtils.md5DigestAsHex(String.valueOf(key).getBytes()));
return accum.toString();
}
/**
* redis key規則字首
*/
private String getKeys() {
return COMMON_CACHE_KEY + this.id + ":*";
}
@Override
public String getId() {
return id;
}
@Override
public void putObject(Object key, Object value) {
final String keyf = getKey(key);
final Object valuef = value;
redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
byte[] keyb = keyf.getBytes();
byte[] valueb = SerializeUtil.serialize(valuef);
connection.set(keyb, valueb);
logger.debug("新增快取 key:--------" + keyf + " liveTime seconds: " + liveTime);
if (liveTime > 0) {
connection.expire(keyb, liveTime);
}
return 1L;
}
});
}
@Override
public Object getObject(Object key) {
final String keyf = getKey(key);
Object object = null;
object = redisTemplate.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] k = keyf.getBytes();
byte[] value = connection.get(k);
if (value == null) {
return null;
}
return SerializeUtil.unserialize(value);
}
});
return object;
}
@Override
public Object removeObject(Object key) {
final String keyf = getKey(key);
Object object = null;
object = redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
logger.debug("移除快取 key:--------" + keyf);
return connection.del(keyf.getBytes());
}
});
return object;
}
@Override
public void clear() {
redisTemplate.execute(new RedisCallback<Integer>() {
@Override
public Integer doInRedis(RedisConnection connection) throws DataAccessException {
Set<byte[]> keys = connection.keys(getKeys().getBytes());
int num = 0;
if (null != keys && !keys.isEmpty()) {
num = keys.size();
for(byte[] k:keys) {
connection.decr(k);
}
}
logger.debug("刪除所有Key字首為 " + getKeys() + "的數目:" + num);
return 1;
}
});
}
@Override
public int getSize() {
Object object = null;
object = redisTemplate.execute(new RedisCallback<Integer>() {
@Override
public Integer doInRedis(RedisConnection connection) throws DataAccessException {
Set<byte[]> keys = connection.keys(getKeys().getBytes());
int num = 0;
if (null != keys && !keys.isEmpty()) {
num = keys.size();
}
logger.debug("查詢所有Key字首為 " + getKeys() + "的數目:" + num);
return num;
}
});
return ((Integer) object).intValue();
}
@Override
public ReadWriteLock getReadWriteLock() {
// TODO Auto-generated method stub
return readWriteLock;
}
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void setId(String id) {
this.id = id;
}
public static class SerializeUtil {
public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static Object unserialize(byte[] bytes) {
if (bytes == null)
return null;
ByteArrayInputStream bais = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
}
3、二級快取的實用
我們需要將所有的實體類進行序列化,然後在Mapper中新增自定義cache功能。自定義的快取類
<cache eviction="LRU" type="com.RedisCache.RedisCache" />
Mapper XML檔案配置支援cache後,檔案中所有的Mapper statement就支援了。此時要個別對待某條,需要:
<select id="inetAton" parameterType="string" resultType="integer" useCache=“false”>
select inet_aton(#{name})
</select>
看如下例子,即一個常用的cache
標籤屬性:
<cache
eviction="FIFO" <!--回收策略為先進先出-->
flushInterval="60000" <!--自動重新整理時間60s-->
size="512" <!--最多快取512個引用物件-->
readOnly="true"/> <!--只讀-->
- 1
- 2
- 3
- 4
- 5
eviction(回收策略)
LRU – 最近最少使用的:移除最長時間不被使用的物件。(預設的屬性)
FIFO – 先進先出:按物件進入快取的順序來移除它們。
SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的物件。
WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的物件。
flushInterval(重新整理間隔)
可以被設定為任意的正整數,而且它們代表一個合理的毫秒形式的時間段。預設情況是不設定,也就是沒有重新整理間隔,快取僅僅呼叫語句時重新整理。
size(引用數目)
可以被設定為任意正整數,要記住你快取的物件數目和你執行環境的可用記憶體資源數目。預設值是1024。
readOnly(只讀)
可以被設定為true或false。只讀的快取會給所有呼叫者返回快取物件的相同例項。因此這些物件不能被修改。這提供了很重要的效能優勢。可讀寫的快取會返回快取物件的拷貝(通過序列化)。這會慢一些,但是安全,因此預設是false。
二、注意的幾個細節
1、如果readOnly為false,此時要結果集物件是可序列化的。
<cache readOnly="false"/>
2、在SqlSession未關閉之前,如果對於同樣條件進行重複查詢,此時採用的是local session cache,而不是上面說的這些cache。
3、MyBatis快取查詢到的結果集物件,而非結果集資料,是將對映的PO物件集合快取起來。
快取使用的註釋方法:
- //配置快取
- @CacheNamespace(size=100,eviction=LruCache.class,implementation=org.mybatis.caches.ehcache.EhcacheCache.class)
- public interface IUsersMapper {
- //開啟快取
- @Options(useCache=true)
- @Select("select * from users")
- public List<Map> findAll();
- @Select("select count(1) from users where userName=#{userName}")
- public int findById(@Param("userName") String userName);
- //儲存過程
- @Select("call pp11()")
- public List<Map> findAll_a();
- }
當時使用 實現 org.springframework.cache.Cache;
在上面吧這個快取管理交給 org.springframework.cache.support.SimpleCacheManager 來管理 啟用註釋即可
package com.redisCache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.concurrent.Callable;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
public class RedisSpringCache implements Cache {
private RedisTemplate<String, Object> redisTemplate;
private String name;
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return this.name;
}
@Override
public Object getNativeCache() {
// TODO Auto-generated method stub
return this.redisTemplate;
}
@Override
public ValueWrapper get(Object key) {
// TODO Auto-generated method stub
System.out.println("get key");
final String keyf = key.toString();
Object object = null;
object = redisTemplate.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = keyf.getBytes();
byte[] value = connection.get(key);
if (value == null) {
return null;
}
return toObject(value);
}
});
return (object != null ? new SimpleValueWrapper(object) : null);
}
@Override
public void put(Object key, Object value) {
// TODO Auto-generated method stub
System.out.println("put key");
final String keyf = key.toString();
final Object valuef = value;
final long liveTime = 86400;
redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
byte[] keyb = keyf.getBytes();
byte[] valueb = toByteArray(valuef);
connection.set(keyb, valueb);
if (liveTime > 0) {
connection.expire(keyb, liveTime);
}
return 1L;
}
});
}
private byte[] toByteArray(Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray();
oos.close();
bos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return bytes;
}
private Object toObject(byte[] bytes) {
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
obj = ois.readObject();
ois.close();
bis.close();
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
return obj;
}
@Override
public void evict(Object key) {
// TODO Auto-generated method stub
System.out.println("del key");
final String keyf = key.toString();
redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.del(keyf.getBytes());
}
});
}
@Override
public void clear() {
// TODO Auto-generated method stub
System.out.println("clear key");
redisTemplate.execute(new RedisCallback<String>() {
public String doInRedis(RedisConnection connection) throws DataAccessException {
connection.flushDb();
return "ok";
}
});
}
@Override
public <T> T get(Object key, Class<T> type) {
// TODO Auto-generated method stub
return null;
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
// TODO Auto-generated method stub
return null;
}
}
附上:轉載的sprigcache的使用: https://blog.csdn.net/u011202334/article/details/61923172
記錄下自己專案在用的Spring Cache的使用方式。
Spring的抽象已經做得夠好了,適合於大多數場景,非常複雜的就需要自己AOP實現了。
Spring官網的文件挺不錯的,但是對Cache這塊的介紹不是很詳細,結合網上大牛的博文,彙總下文。
快取概念
快取簡介
快取,我的理解是:讓資料更接近於使用者;工作機制是:先從快取中讀取資料,如果沒有再從慢速裝置上讀取實際資料(資料也會存入快取);快取什麼:那些經常讀取且不經常修改的資料/那些昂貴(CPU/IO)的且對於相同的請求有相同的計算結果的資料。如CPU—L1/L2—記憶體—磁碟就是一個典型的例子,CPU需要資料時先從 L1/L2中讀取,如果沒有到記憶體中找,如果還沒有會到磁碟上找。還有如用過Maven的朋友都應該知道,我們找依賴的時候,先從本機倉庫找,再從本地伺服器倉庫找,最後到遠端倉庫伺服器找;還有如京東的物流為什麼那麼快?他們在各個地都有分倉庫,如果該倉庫有貨物那麼送貨的速度是非常快的。
快取命中率
即從快取中讀取資料的次數 與 總讀取次數的比率,命中率越高越好:
命中率 = 從快取中讀取次數 / (總讀取次數[從快取中讀取次數 + 從慢速裝置上讀取的次數])
Miss率 = 沒有從快取中讀取的次數 / (總讀取次數[從快取中讀取次數 + 從慢速裝置上讀取的次數])這是一個非常重要的監控指標,如果做快取一定要健康這個指標來看快取是否工作良好;
快取策略
Eviction policy
移除策略,即如果快取滿了,從快取中移除資料的策略;常見的有LFU、LRU、FIFO:
- FIFO(First In First Out):先進先出演算法,即先放入快取的先被移除;
- LRU(Least Recently Used):最久未使用演算法,使用時間距離現在最久的那個被移除;
- LFU(Least Frequently Used):最近最少使用演算法,一定時間段內使用次數(頻率)最少的那個被移除;
TTL(Time To Live )
存活期,即從快取中建立時間點開始直到它到期的一個時間段(不管在這個時間段內有沒有訪問都將過期)
TTI(Time To Idle)
空閒期,即一個數據多久沒被訪問將從快取中移除的時間。
到此,基本瞭解了快取的知識,在Java中,我們一般對呼叫方法進行快取控制,比如我呼叫”findUserById(Long id)”,那麼我應該在呼叫這個方法之前先從快取中查詢有沒有,如果沒有再掉該方法如從資料庫載入使用者,然後新增到快取中,下次呼叫時將會從快取中獲取到資料。
自Spring 3.1起,提供了類似於@Transactional註解事務的註解Cache支援,且提供了Cache抽象;在此之前一般通過AOP實現;使用Spring Cache的好處:
- 提供基本的Cache抽象,方便切換各種底層Cache;
- 通過註解Cache可以實現類似於事務一樣,快取邏輯透明的應用到我們的業務程式碼上,且只需要更少的程式碼就可以完成;
- 提供事務回滾時也自動回滾快取;
- 支援比較複雜的快取邏輯;
對於Spring Cache抽象,主要從以下幾個方面學習:
快取簡介 開濤的部落格
- Cache API及預設提供的實現
- Cache註解
- 實現複雜的Cache邏輯
Spring Cache簡介
Spring3.1開始引入了激動人心的基於註釋(annotation)的快取(cache)技術,它本質上不是一個具體的快取實現方案(例如EHCache 或者 OSCache),而是一個對快取使用的抽象,通過在既有程式碼中新增少量它定義的各種 annotation,即能夠達到快取方法的返回物件的效果。
Spring的快取技術還具備相當的靈活性,不僅能夠使用 SpEL(Spring Expression Language)來定義快取的key和各種condition,還提供開箱即用的快取臨時儲存方案,也支援和主流的專業快取例如EHCache、 memcached整合。
其特點總結如下:
Spring Cache 介紹 Spring Cache 介紹 - Rollen Holt - 部落格園
- 通過少量的配置 annotation 註釋即可使得既有程式碼支援快取
- 支援開箱即用 Out-Of-The-Box,即不用安裝和部署額外第三方元件即可使用快取
- 支援 Spring Express Language,能使用物件的任何屬性或者方法來定義快取的 key 和 condition
- 支援 AspectJ,並通過其實現任何方法的快取支援
- 支援自定義 key 和自定義快取管理者,具有相當的靈活性和擴充套件性
API介紹
Cache介面
理解這個介面有助於我們實現自己的快取管理器
[java] view plain copy- package org.springframework.cache;
- public interface Cache {
- /**
- * 快取的名字
- */
- String getName();
- /**
- * 得到底層使用的快取
- */
- Object getNativeCache();
- /**
- * 根據key得到一個ValueWrapper,然後呼叫其get方法獲取值
-
相關推薦
spring+ mybatis 二級快取使用 redis作為快取
springMybatisConfig.xml配置 <?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="ht
spring,springmvc,mybatis整合redis,redis作為快取使用
環境 1,windows7 2,mysql 3,eclipse 4,redis 5,tomcat7 注意:啟動redis的方式,已經把redis做成windows服務,以windows服務的方式啟動 把redis做成windows服務的命令列 redis-s
mybatis plus使用redis作為二級快取
建議快取放到 service 層,你可以自定義自己的 BaseServiceImpl 重寫註解父類方法,繼承自己的實現。為了方便,這裡我們將快取放到mapper層。mybatis-plus整合redis作為二級快取與mybatis整合redis略有不同。 1. mybatis-plus開啟二級快取 mybat
REDIS學習(3.2)spring boot 使用redis作為快取
一,指定主鍵的生成規則 在3.1的基礎上修改RedisConfig @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Be
spring-boot整合redis作為快取(3)——自定義key
分幾篇文章總結spring-boot與Redis的整合 4、自定義key 5、spring-boot引入Redis 在上一篇文章中說道key是用來分辨同一個快取中的快取資料的。key是可以自己制定的,也
從零搭建Spring Boot腳手架(6):整合Redis作為快取
![](https://img2020.cnblogs.com/other/1739473/202008/1739473-20200819095515507-188579634.png) ## 1. 前言 [上一文](https://mp.weixin.qq.com/s/9uVsi9yfE0QheEKCU
Redis作為快取實現工具類
使用Redis作為快取物件,常用的儲存格式為字串,所以在儲存快取時,將物件轉為字串儲存.由於存的時候為字串,所以取出的也為json字串. 此工具類在設值時只需要將key與物件傳入即可 取值時只需要將key與要取的物件型別傳入即可 public class CacheUtilImpl im
讀取大檔案資料進入redis作為快取:贈(廣播變數)
在專案中使用Redis做快取檔案(目的等同於廣播變數): package com.app import com.utils.{JedisConnectionPool, RptUtils} import org.apache.commons.lang.StringUtils import
Spring boot如何使用redis做快取及快取註解的用法總結
1. 概述 本文介紹Spring boot 如何使用redis做快取,如何對redis快取進行定製化配置(如key的有效期)以及spring boot 如
SpringBoot 2.x 使用Redis作為快取 設定有效時間
redis 配置 redis: database: 0 host: localhost port: 6379 password: jedis: pool: max-active: 8 max-wait:
Spring boot中使用Redis實現快取功能
1. Redis簡介 Redis是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。 Redis 可以儲存鍵與5種不同資料結構型別之間的對映,這5種資料結構型別分別為String(
springboot2+shiro+jwt整合(二)細粒度許可權控制+使用redis作為快取
簡單來說,當專案啟動起來後,我們的後臺介面的許可權控制就應該起作用了,那麼如何使用shiro來實現呢?我這裡使用的是 如何使用註解來配置細粒度許可權。 首先,shiro預設不支援使用註解方式,需要在ShiroConfig中新增以下程式碼 /** * 下面
Shiro使用redis作為快取(解決shiro頻繁訪問Redis)(十一)
之前寫過一篇部落格,使用的一個開源專案,實現了redis作為快取 快取使用者的許可權 和 session資訊,還有兩個功能沒有修改,一個是使用者併發登入限制,一個是使用者密碼錯誤次數.本篇中幾個類 也是使用的開源專案中的類,只不過是拿出來了,redis單獨做
springboot配置redis作為快取空間
package com.ty.tyzxtj.util; import java.io.Serializable; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import org.sprin
redis作為快取的簡單理解
來源:http://doushini.iteye.com/blog/1879616?utm_source=tuicool&utm_medium=referral Redis快取伺服器筆記 redis是一個高效能的key-value儲存系統,能夠作為快取框架和佇列
springboot2.x使用redis作為快取(使用fastjson序列化的方式,並除錯反序列化異常
1.redis是記憶體資料庫,可以單獨作為資料庫(有持久化方案),也可以作為快取(一般為MySQL搭配) 1.1 可以通過jedis,程式碼的方式手動將其傳入redis作為快取; 1.2 也可以通過註解的方式,和spring boo
nodejs使用redis作為快取介質,封裝快取類
// cache.js const redis = require('redis'); const config = require('config'); const logger = require('winston'); const redisObj = { client: null,
大型分布式項目項目實戰Springmvc+Spring+Mybatis+Maven+CMS+Redis+Solr+Linux+Nginx+單點登錄、分布式緩存、負載均衡視頻課程
edi mina img solr 技術 性能提升 登錄 rom nginx * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架構師、集群、高可用、高可擴 展、高性能、高
redis作為mybatis的二級快取
redis作為二級快取伺服器,來替代mybatis的二級快取,至於二級快取有什麼缺點我想大家都懂吧, [service] 2016-08-31 21:01:32,912 - com.erp.dao.TestMybatisMapper.selectByPrimaryKey -19
Spring Boot + Mybatis + 二級快取例項(Ehcache,Redis)
使用Mybatis自帶二級快取 MyBatis 包含一個非常強大的查詢快取特性,它可以非常方便地配置和定製。MyBatis 3 中的快取實現的很多改進都已經實現了,使得它更加強大而且易於配置。 預設情況下是沒有開啟快取的,除了區域性的 session 快取,可以增強