redis之20分鐘輕鬆搞定springCache緩存(單機+集羣)
原文地址:https://m.baidu.com/from=1013843a/bd_page_type=1/ssid=0/uid=0/pu=sz%401321_1002%2Cta%40utouch_2_7.0_2_7.3%2Cusm%401/baiduid=9B4ABF6E3921A8D5A4D61ED28BC57185/w=0_10_/t=wap/l=3/tc?ref=www_utouch&lid=9194807654318041054&order=4&h5ad=0&tj=www_normal_4_0_10_1&vit=osres&m=8&srd=1&title=redis%E4%B9%8B20%E5%88%86%E9%92%9F%E8%BD%BB%E6%9D%BE%E6%90%9E%E5%AE%9AspringCache%E7%BC%93%E5%AD%98%28%E5%8D%95%E6%9C%BA%2B%E9%9B%86%E7%BE%A4%29&dict=32&wd=&eqid=7f9a84d86dab6800100000025ad3605a&w_qd=IlPT2AEptyoA_yiZH5_eIyYtvQbSq-dIoUlZ&tcplug=1&sec=29078&di=5624e693a16782a6&bdenc=1&nsrc=IlPT2AEptyoA_yixCFOxCGZb8c3JV3T5ABSULCRR1z_voo3-efnbFRhdXTqqAp7JZpLPvWL0sakExXyi_WYn7xpCqalhtWkg78XhgPrux14ACBVdv1Ex0tPUDXBu6u4gyKpOtQS
1. redis(單機版)實現spring緩存
1.1. 環境準備
使用maven搭建一套ssm框架,並創建測試類查詢emp表。測試代碼如下:
/**
* @不開啓springCache
*/
publicstaticvoid main(String[] args) {
ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml");
EmpBiz empBiz=(EmpBiz) ac.getBean("empBizImpl");
Long begin=System.currentTimeMillis();
List empList = empBiz.findAllEmp();
System.out.println("員工數:"+empList.size());
Long end=System.currentTimeMillis();
System.out.println("花費時間:"+(end-begin));
}
結果截圖:
1.2. 配置spring緩存
1) 修改配置文件pom.xml
4.3.3.RELEASE
redis.clients
jedis
2.9.0
org.springframework.data
spring-data-redis
1.7.4.RELEASE
2) 修改配置文件applicationContext.xml,掃描service層
3) 添加配置文件spring-redis.xml
4) 創建spring cache接口的實現類SpringRedisCache
/**
* @author TeacherChen
* @description springcache的實現類
* @company AAA軟件
* 2018-1-13下午2:07:15
*/
publicclass SpringRedisCache implements Cache {
private RedisTemplate redisTemplate;
private String name;
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
publicvoid setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
publicvoid setName(String name) {
this.name = name;
}
@Override
public String getName() {
// TODO Auto-generated method stub
returnthis.name;
}
@Override
public Object getNativeCache() {
// TODO Auto-generated method stub
returnthis.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() {
public Object doInRedis(RedisConnection connection)
throws DataAccessException {
byte[] key = keyf.getBytes();
byte[] value = connection.get(key);
if (value == null) {
returnnull;
}
return toObject(value);
}
});
return (object != null ? new SimpleValueWrapper(object) : null);
}
@Override
publicvoid put(Object key, Object value) {
// TODO Auto-generated method stub
System.out.println("put key");
final String keyf = key.toString();
final Object valuef = value;
finallong liveTime = 86400;
redisTemplate.execute(new RedisCallback() {
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;
}
});
}
privatebyte[] 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
publicvoid evict(Object key) {
// TODO Auto-generated method stub
System.out.println("del key");
final String keyf = key.toString();
redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection)
throws DataAccessException {
return connection.del(keyf.getBytes());
}
});
}
@Override
publicvoid clear() {
// TODO Auto-generated method stub
System.out.println("clear key");
redisTemplate.execute(new RedisCallback() {
public String doInRedis(RedisConnection connection)
throws DataAccessException {
connection.flushDb();
return "ok";
}
});
}
@Override
public T get(Object key, Class type) {
// TODO Auto-generated method stub
returnnull;
5) }
6) 測試類
要在需要緩存的方法或者類上加緩存註解
@Cacheable
/**
* @開啓springCache
*/
publicstaticvoid main(String[] args) {
ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml","spring-redis.xml");
EmpBiz empBiz=(EmpBiz) ac.getBean("empBizImpl");
Long begin=System.currentTimeMillis();
List empList = empBiz.findAllEmp();
System.out.println("員工數:"+empList.size());
Long end=System.currentTimeMillis();
System.out.println("花費時間:"+(end-begin));
}
7) 測試效果
第一次查詢
第二次查詢
8) spring緩存註解@Cacheable
可以標記在一個方法上,也可以標記在一個類上。當標記在一個方法上時表示該方法是支持緩存的,當標記在一個類上時則表示該類所有的方法都是支持緩存的(value key condition)
value屬性是必須指定的,其表示當前方法的返回值是會被緩存在哪個Cache上的,對應Cache的名稱。其可以是一個Cache也可以是多個Cache,當需要指定多個Cache時其是一個數組。
key屬性是用來指定Spring緩存方法的返回結果時對應的key的。該屬性支持SpringEL表達式。當我們沒有指定該屬性時,Spring將使用默認策略生成key。
/**
* 按照員工編號查詢員工信息,juan是緩存的名稱,#empno是緩存的key,返回值Emp對象是緩存的值
* @param empno
* @return emp
*/
@Override
@Cacheable(value="juan",key="#empno")
public Emp selectByPrimaryKey(Short empno) {
return empMapper.selectByPrimaryKey(empno);
}
condition有的時候我們可能並不希望緩存一個方法所有的返回結果。通過condition屬性可以實現這一功能。condition屬性默認爲空,表示將緩存所有的調用情形。其值是通過SpringEL表達式來指定的,當爲true時表示進行緩存處理;當爲false時表示不進行緩存處理,即每次調用該方法時該方法都會執行一次。如下示例表示只有當empno爲偶數時纔會進行緩存。
/**
* 按照員工編號查詢員工信息,juan是緩存的名稱,#empno是緩存的key,返回值Emp對象是緩存的值
* condition="#empno%2==0"緩存工號爲偶數的員工信息,奇數不緩存
* @param empno
* @return emp
*/
@Override
@Cacheable(value="juan",key="#empno",condition="#empno%2==0")
public Emp selectByPrimaryKey(Short empno) {
return empMapper.selectByPrimaryKey(empno);
}
9) spring緩存註解@CacheEvict
是用來標註在需要清除緩存元素的方法或類上的。當標記在一個類上時表示其中所有的方法的執行都會觸發緩存的清除操作
/**
* 按照員工編號刪除員工,並清除對應的緩存
* @param empno
*/
@Override
@CacheEvict(value="juan",key="#empno")
publicvoid deleteByPrimaryKey(Short empno) {
empMapper.deleteByPrimaryKey(empno);
}
10) spring緩存註解@CachePut
CachePut也可以聲明一個方法支持緩存功能。與@Cacheable不同的是使用@CachePut標註的方法在執行前不會去檢查緩存中是否存在之前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的緩存中。
/**
* 修改員工信息,並同步更新緩存中的員工信息
* @CachePut不管緩存中有沒有,沒有的話放入緩存,有的話替換緩存
*/
@Override
@CachePut(value="juan",key="#emp.empno")
public Emp updateByPrimaryKeySelective(Emp emp) {
empMapper.updateByPrimaryKey(emp);
return emp;
}
測試步驟,
首先不加@CachePut(value="juan",key="#emp.empno"),查詢一條數據,這條數據自動緩存到redis,然後修改這條數據,再次查詢數據庫變化,緩存不變,查詢的結果不對。
加上@CachePut(value="juan",key="#emp.empno"),再次修改同一條數據,查詢發現數據庫和緩存同步修改。
2. redis(集羣版)實現spring緩存
2.1. 修改配置文件spring-redis.xml
2.2. 測試效果
1) 啓動redis集羣
redis-server /usr/local/redis_cluster/7001/redis.confredis-server /usr/local/redis_cluster/7002/redis.confredis-server /usr/local/redis_cluster/7003/redis.confredis-server /usr/local/redis_cluster/7004/redis.confredis-server /usr/local/redis_cluster/7005/redis.confredis-server /usr/local/redis_cluster/7006/redis.conf
2) 清空集羣中的所有key,要在主節點上操作
使用FLUSHALL命令在所有的主節點
3) 第一次查詢
查看redis集羣發現緩存已經存在
4) 第二次查詢
後記:redis先講這麼多,後面會給大家介紹mysql數據庫的主從複製和讀寫分離,敬請關注。