您的位置:首页 > 数据库 > Redis

spring-data-redis 自定义注解扩展实现时效设置

2017-06-13 08:19 656 查看

前言

spring目前在@Cacheable和@CacheEvict等注解上不支持缓存时效设置,只允许通过配置文件设置全局时效。这样就很不方便设定时间。比如系统参数和业务数据的时效是不一样的,这给程序开发造成很大的困扰。不得已,本人实现了类似Sping的三个注解。以下是具体实现。

工程下载>>>

实现

1、注解类的实现

package com.example.spring.boot.redis.annotation;

import java.lang.annotation.*;

/**
* Author: 王俊超
* Date: 2017-06-10 05:56
* All Rights Reserved !!!
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisCacheEvict {

/**
* 缓存名称
*
* @return
*/
String cacheName();

/**
* 缓存key
*
* @return
*/
String key();
}


package com.example.spring.boot.redis.annotation;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
* Author: 王俊超
* Date: 2017-06-10 05:56
* All Rights Reserved !!!
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisCacheGet {

/**
* 缓存名称
*
* @return
*/
String cacheName();

/**
* 缓存key
*
* @return
*/
String key();

/**
* 缓存过期时间
*
* @return
*/
int expire() default 0;

/**
* 缓存的时间单位
*
* @return
*/
TimeUnit timeUnit();
}


package com.example.spring.boot.redis.annotation;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
* Author: 王俊超
* Date: 2017-06-10 05:56
* All Rights Reserved !!!
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisCachePut {

/**
* 缓存名称
*
* @return
*/
String cacheName();

/**
* 缓存key
*
* @return
*/
String key();

/**
* 缓存过期时间
*
* @return
*/
int expire() default 0;

/**
* 缓存的时间单位
*
* @return
*/
TimeUnit timeUnit();
}


2、切面代码实现

package com.example.spring.boot.redis.aspect;

import com.example.spring.boot.redis.annotation.RedisCacheEvict;
import com.example.spring.boot.redis.annotation.RedisCacheGet;
import com.example.spring.boot.redis.annotation.RedisCachePut;
import com.example.spring.boot.redis.common.RedisClient;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

/**
* 缓存处理时间切面
*
* Author: 王俊超
* Date: 2017-06-10 06:17
* All Rights Reserved !!!
*/
@Aspect
public class RedisCacheAspect {
private final static char DOT = '.';
private final static char SHARP = '#';
private RedisClient redisClient;

public RedisClient getRedisClient() {
return redisClient;
}

public void setRedisClient(RedisClient redisClient) {
this.redisClient = redisClient;
}

/**
* 对象入缓存
* @param pjp
* @param cachePut
* @return
* @throws Throwable
*/
@Around("@annotation(cachePut)")
public Object cachePut(ProceedingJoinPoint pjp, RedisCachePut cachePut) throws Throwable {
Object keyObject = getCacheKey(pjp, cachePut.key());
Object result = pjp.proceed();

// 不为空才保存数据
if (result != null && keyObject != null){
redisClient.set(cachePut.cacheName(), keyObject, result, cachePut.expire());
}

return result;
}

/**
* 优先从缓存中取对象
*
* @param pjp
* @param cacheGet
* @return
* @throws Throwable
*/
@Around("@annotation(cacheGet)")
public Object cacheGet(ProceedingJoinPoint pjp, RedisCacheGet cacheGet) throws Throwable {
Object keyObject = getCacheKey(pjp, cacheGet.key());
Object result = redisClient.get(cacheGet.cacheName(), keyObject);
// 如果从缓存中没有取到数据,就从调用方法获取数据
if (result == null) {
result = pjp.proceed();

// 方法的返回值不是void类型,就要将结果入缓存
Class clz = getAdvicedMethod(pjp).getReturnType();
if (clz != Void.class) {
redisClient.set(cacheGet.cacheName(), keyObject, result, cacheGet.expire());
}
}

return result;
}

/**
* 删除缓存
*
* @param pjp
* @param cacheEvict
* @return
* @throws Throwable
*/
@Around("@annotation(cacheEvict)")
public Object cacheEvict(ProceedingJoinPoint pjp, RedisCacheEvict cacheEvict) throws Throwable {
Object keyObject = getCacheKey(pjp, cacheEvict.key());
redisClient.del(cacheEvict.cacheName(), keyObject);
return pjp.proceed();
}

/**
* 获取缓存的key对象
*
* @param pjp
* @param key
* @return
* @throws Exception
*/
private Object getCacheKey(ProceedingJoinPoint pjp, String key) throws Exception {
// 以#开头
if (key.length() > 0 && key.charAt(0) == SHARP) {
// 去掉#
key = key.substring(1);
// 将key分割成属性和参数名,第一个“.”之前是参数名,之后是属性名称
int dotIdx = key.indexOf(DOT);
String argName = key;
if (dotIdx > 0) {
argName = key.substring(0, dotIdx);
key = key.substring(dotIdx + 1); // 剩下的属性
}

// 取参数值
Object argVal = getArg(pjp, argName);

// 获取参数的属性值
Object objectKey = argVal;
if (dotIdx > 0) {
objectKey = getObjectKey(argVal, key);
}

return objectKey;

} else { // 不是以#开头的就以其值作为参数key
return key;
}
}

/**
* 获取参数对象
*
* @param pjp 连接点
* @param parameterName 参数名称
* @return
*/
private Object getArg(ProceedingJoinPoint pjp, String parameterName) throws NoSuchMethodException {

Method method = getAdvicedMethod(pjp);
ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
if (parameterNames != null) {
int idx = 0;
for (String name : parameterNames) {
if (name.equals(parameterName)) {
return pjp.getArgs()[idx];
}
idx++;
}
}

throw new IllegalArgumentException("no such parameter name: [" + parameterName + "] in method: " + method);
}

/**
* 获取拦截的方法
*
* @param pjp 连接点
* @return
* @throws NoSuchMethodException
*/
private Method getAdvicedMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
Signature sig = pjp.getSignature();
MethodSignature msig = null;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("annotation can only use to method.");
}
msig = (MethodSignature) sig;
Object target = pjp.getTarget();
return target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
}

/**
* 获取从object上获取key所对应的属性对象
* 例如:key: country.province.city.town
* 就相当于调用:object.getCountry().getProvince().getCity.getTown()
*
* @param object
* @param key
* @return
* @throws Exception
*/
private Object getObjectKey(Object object, String key) throws Exception {
// 如果key已经是空了就直接返回
if (StringUtils.isEmpty(key)) {
return object;
}

int dotIdx = key.indexOf(DOT);
// 形如key=aa.bb**的情况
if (dotIdx > 0) {
// 取第一个属性值
String propertyName = key.substring(0, dotIdx);
// 取剩下的key
key = key.substring(dotIdx + 1);

Object property = getProperty(object, getterMethod(propertyName));
return getObjectKey(property, key);
} else { // key=aa
return getProperty(object, getterMethod(key));
}
}

/**
* 获取name的getter方法名称
*
* @param name
* @return
*/
private String getterMethod(String name) {
return "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
}

/**
* 调用obj对象上的getterMethodName
*
* @param obj
* @param getterMethodName
* @return
* @throws Exception
*/
private Object getProperty(Object obj, String getterMethodName) throws Exception {
return obj.getClass().getMethod(getterMethodName).invoke(obj);
}
}


3、工具类实现

package com.example.spring.boot.redis.common;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

/**
* 序列化和反序列化工具
*
* Author: 王俊超
* Date: 2017-05-31 21:43
* All Rights Reserved !!!
*/
public class KryoRedisSerializer<T> implements RedisSerializer<T> {
private Kryo kryo = new Kryo();

@Override
public byte[] serialize(T t) throws SerializationException {
byte[] buffer = new byte[2048];
Output output = new Output(buffer);
kryo.writeClassAndObject(output, t);
byte[] result = output.toBytes();
output.close();
return result;
}

@Override
public T deserialize(byte[] bytes) throws SerializationException {
Input input = new Input(bytes);
@SuppressWarnings("unchecked")
T t = (T) kryo.readClassAndObject(input);
input.close();
return t;
}

}


package com.example.spring.boot.redis.common;

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.data.redis.serializer.RedisSerializer;

import java.util.Set;

/**
* Redis客户端实现工具
*
* Author: 王俊超
* Date: 2017-06-04 19:57
* All Rights Reserved !!!
*/

public class RedisClientImpl implements RedisClient {
private RedisTemplate<Object, Object> redisTemplate;
private RedisSerializer<Object> keySerializer;
private RedisSerializer<Object> valSerializer;

public RedisTemplate<Object, Object> getRedisTemplate() {
return redisTemplate;
}

public void setRedisTemplate(RedisTemplate<Object, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}

public RedisSerializer<Object> getKeySerializer() {
return keySerializer;
}

public void setKeySerializer(RedisSerializer<Object> keySerializer) {
this.keySerializer = keySerializer;
}

public RedisSerializer<Object> getValSerializer() {
return valSerializer;
}

public void setValSerializer(RedisSerializer<Object> valSerializer) {
this.valSerializer = valSerializer;
}

/////////////////////////////////////

/**
* 获取最终的key
*
* @param cacheName
* @param key
* @return
*/
private byte[] getRealKey(Object cacheName, Object key) {
byte[] b1 = keySerializer.serialize(cacheName);
byte[] b2 = keySerializer.serialize(key);
byte[] result = new byte[b1.length + b2.length];
System.arraycopy(b1, 0, result, 0, b1.length);
System.arraycopy(b2, 0, result, b1.length, b2.length);
return result;
}

/**
* 获取真实key
* @param cacheName
* @param key
* @return
*/
private byte[] getRealKey(byte[] cacheName, Object key) {
byte[] b2 = keySerializer.serialize(key);
byte[] result = new byte[cacheName.length + b2.length];
System.arraycopy(cacheName, 0, result, 0, cacheName.length);
System.arraycopy(b2, 0, result, cacheName.length, b2.length);

return result;
}

@Override
public long del(Object cacheName, Object... keys) {
return redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
byte[] b1 = keySerializer.serialize(cacheName);
long result = 0;
for (Object o : keys) {
result += connection.del(getRealKey(b1, o));
}
return result;
}
});
}

@Override
public void set(byte[] key, byte[] value, long liveTime) {
redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.set(key, value);
if (liveTime > 0) {
connection.expire(key, liveTime);
}
return true;
}
});
}

@Override
public void set(Object cacheName, Object key, Object value, long liveTime) {
this.set(getRealKey(cacheName, key), valSerializer.serialize(value), liveTime);
}

@Override
public void set(Object cacheName, Object key, Object value) {
this.set(cacheName, key, value, 0L);
}

@Override
public void set(byte[] key, byte[] value) {
this.set(key, value, 0L);
}

/**
* 获取redis value (String)
*
* @param key
* @return
*/

@Override
public <T> T get(byte[] key) {
return redisTemplate.execute(new RedisCallback<T>() {
@Override
public T doInRedis(RedisConnection connection) throws DataAccessException {
byte[] result = connection.get(key);
Object obj = null;
if (result != null) {
obj = valSerializer.deserialize(result);
}

return (T) obj;
}
});
}

@Override
public <T> T get(Object cacheName, Object key) {
return this.get(getRealKey(cacheName, key));
}

@Override
public Set keys(byte[] pattern) {
return redisTemplate.execute(new RedisCallback<Set>() {
@Override
public Set doInRedis(RedisConnection connection) throws DataAccessException {
return connection.keys(pattern);
}
});
}

@Override
public Set keys(String pattern) {
return this.keys(keySerializer.serialize(pattern));
}

@Override
public boolean exists(byte[] key) {
return redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.exists(key);
}
});
}

@Override
public boolean exists(Object cacheName, Object key) {
return this.exists(getRealKey(cacheName, key));
}

@Override
public boolean flushDb() {
return redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.flushDb();
return true;
}
});
}

@Override
public long dbSize() {
return redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.dbSize();
}
});
}

@Override
public String ping() {
return redisTemplate.execute(new RedisCallback<String>() {
public String doInRedis(RedisConnection connection) throws DataAccessException {
return connection.ping();
}
});
}
}


4、应用配置

package com.example.spring.boot.redis;

import com.example.spring.boot.redis.aspect.RedisCacheAspect;
import com.example.spring.boot.redis.common.KryoRedisSerializer;
import com.example.spring.boot.redis.common.RedisClient;
import com.example.spring.boot.redis.common.RedisClientImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;

/**
* Author: 王俊超
* Date: 2017-05-07 10:02
* All Rights Reserved !!!
*/
@Configuration
public class AppConfig {

/**
* Redis连接工厂
*
* @return
*/
@Primary
@Bean("redisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory() {

// Redis集群地址
List<String> clusterNodes = Arrays.asList("192.168.241.150:7110",
"192.168.241.150:7111", "192.168.241.150:7112", "192.168.241.150:7113",
"192.168.241.150:7114", "192.168.241.150:7115", "192.168.241.150:7116",
"192.168.241.150:7117", "192.168.241.150:7118", "192.168.241.150:7119"
);

// 获取Redis集群配置信息
RedisClusterConfiguration rcf = new RedisClusterConfiguration(clusterNodes);
return new JedisConnectionFactory(rcf);
}

/**
* 创建redis模板
*
* @param factory
* @return
* @throws UnknownHostException
*/
@Primary
@Bean("redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);

// 可根据需要设置
//        // redis value使用的序列化器
//        template.setValueSerializer(new KryoRedisSerializer<>());
//        template.setHashKeySerializer(new KryoRedisSerializer<>());
//        // redis key使用的序列化器
//        template.setKeySerializer(new KryoRedisSerializer<>());
//        template.setHashValueSerializer(new KryoRedisSerializer<>());

template.afterPropertiesSet();
return template;
}

/**
* 返回redis客户端
*
* @param redisTemplate
* @return
*/
@Bean
public RedisClient redisClient(RedisTemplate<Object, Object> redisTemplate) {
RedisClientImpl redisClient = new RedisClientImpl();
redisClient.setRedisTemplate(redisTemplate);
KryoRedisSerializer<Object> serializer = new KryoRedisSerializer<>();
redisClient.setKeySerializer(serializer);
redisClient.setValSerializer(serializer);

return redisClient;
}

/**
* redis缓存的切面
* @param redisClient
* @return
*/
@Bean
public RedisCacheAspect redisCacheAspect(RedisClient redisClient) {
RedisCacheAspect aspect = new RedisCacheAspect();
aspect.setRedisClient(redisClient);
return aspect;
}
}


5、应用的启动

package com.example.spring.boot.redis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
* Author: 王俊超
* Date: 2017-05-07 10:04
* All Rights Reserved !!!
*/
@SpringBootApplication
@EnableTransactionManagement
@EnableCaching
@EnableAutoConfiguration
//@EnableAspectJAutoProxy
public class AppRunner {

public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(AppRunner.class, args);
}
}


6、配置文件

server.context-path=/redis/cache
# 开启AOP
spring.aop.auto=true


测试

1、测试数据

package com.example.spring.boot.redis.entity;

/**
* 县
* Author: 王俊超
* Date: 2017-06-12 20:06
* All Rights Reserved !!!
*/
public class City {
private long id;
private String name;
private Province province;

public City() {
}

public City(long id, String name, Province province) {
this.id = id;
this.name = name;
this.province = province;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Province getProvince() {
return province;
}

public void setProvince(Province province) {
this.province = province;
}
}


package com.example.spring.boot.redis.entity;

/**
* 国家
* Author: 王俊超
* Date: 2017-06-12 20:06
* All Rights Reserved !!!
*/
public class Country {
private long id;
private String name;

public Country() {
}

public Country(long id, String name) {
this.id = id;
this.name = name;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


package com.example.spring.boot.redis.entity;

/**
* 省
* Author: 王俊超
* Date: 2017-06-12 20:06
* All Rights Reserved !!!
*/
public class Province {
private long id;
private String name;
private Country country;

public Province() {
}

public Province(long id, String name, Country country) {
this.id = id;
this.name = name;
this.country = country;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Country getCountry() {
return country;
}

public void setCountry(Country country) {
this.country = country;
}
}


package com.example.spring.boot.redis.entity;

/**
* 镇
* Author: 王俊超
* Date: 2017-06-12 20:06
* All Rights Reserved !!!
*/
public class Town {
private long id;
private String name;
private City city;

public Town() {
}

public Town(long id, String name, City city) {
this.id = id;
this.name = name;
this.city = city;
}

public long getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public City getCity() {
return city;
}

public void setCity(City city) {
this.city = city;
}
}


package com.example.spring.boot.redis;

import com.example.spring.boot.redis.annotation.RedisCacheEvict;
import com.example.spring.boot.redis.annotation.RedisCacheGet;
import com.example.spring.boot.redis.annotation.RedisCachePut;
import com.example.spring.boot.redis.entity.City;
import com.example.spring.boot.redis.entity.Country;
import com.example.spring.boot.redis.entity.Province;
import com.example.spring.boot.redis.entity.Town;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
* Author: 王俊超
* Date: 2017-06-10 06:26
* All Rights Reserved !!!
*/
@Component
public class TestData {

public  final static Country COUNTRY = new Country(111111, "CHINA");
public  final static Province PROVINCE = new Province(222222, "GuangZhou", COUNTRY);
public  final static City CITY = new City(333333, "ShenZhen", PROVINCE);
public  final static Town TOWN = new Town(444444, "Where", CITY);

public final static String LOCATION = "location";

@RedisCachePut(cacheName = LOCATION, key = "#town.city.province.country.id",
expire = 60, timeUnit = TimeUnit.SECONDS)
public Country createCountry(Town town) {
return town.getCity().getProvince().getCountry();
}

@RedisCacheGet(cacheName = LOCATION, key = "#id", expire = 60, timeUnit = TimeUnit.SECONDS)
public Country getCountry(long id) {
return COUNTRY;
}

@RedisCacheEvict(cacheName = LOCATION, key = "#id")
public void deleteCountry(long id) {
// 清除缓存
}
}


2、测试用例

import com.example.spring.boot.redis.AppRunner;
import com.example.spring.boot.redis.TestData;
import com.example.spring.boot.redis.common.KryoRedisSerializer;
import com.example.spring.boot.redis.common.RedisClient;
import com.example.spring.boot.redis.entity.Country;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
* Author: 王俊超
* Date: 2017-06-12 21:10
* All Rights Reserved !!!
*/
@RunWith(SpringRunner.class)
@SpringBootTest( classes = AppRunner.class)
public class TestRunner {
@Autowired
RedisClient redisClient;

@Autowired
TestData testData;

/**
* 测试序列化,反序列化
*/
@Test
public void testSerialize() {
Country c1 = testData.createCountry(TestData.TOWN);
KryoRedisSerializer<Object> serializer = new KryoRedisSerializer<>();
byte[] b1 = serializer.serialize(c1);
Country c2 = (Country) serializer.deserialize(b1);
Assert.assertNotNull(c2);
Assert.assertEquals(c1.getId(), c2.getId());
Assert.assertEquals(c1.getName(), c2.getName());
}

@Test
public void testCachePut() {

// 先清理缓存
redisClient.del(TestData.LOCATION, TestData.COUNTRY.getId());
Country c = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
Assert.assertNull(c);

// 创建一个国家
Country c1 = testData.createCountry(TestData.TOWN);

// 直接从缓存中取数据,说明数据已经入缓存
Country c2 = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
Assert.assertNotNull(c2);
Assert.assertEquals(c1.getId(), c2.getId());
Assert.assertEquals(c1.getName(), c2.getName());

}

@Test
public void testCacheGet() {
// 先清理缓存
redisClient.del(TestData.LOCATION, TestData.COUNTRY.getId());
Country c = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
Assert.assertNull(c);

// 取数据
Country c1 = testData.getCountry(TestData.COUNTRY.getId());
// 从缓存中取
Country c2 = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());

Assert.assertNotNull(c2);
Assert.assertEquals(c1.getId(), c2.getId());
Assert.assertEquals(c1.getName(), c2.getName());
}

@Test
public void testCacheEvict() {
// 创建一个国家
Country c = testData.createCountry(TestData.TOWN);
redisClient.del(TestData.LOCATION, TestData.COUNTRY.getId());
c = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
Assert.assertNull(c);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: