目录
配置
具体实现
用户实体类
接口
接口实现类
缓存注解说明
@CachePut
@Cacheable
@CacheEvict
测试结果
saveUser
getUser
updateUser
removeUser
配置
首先在POM文件中加入Redis相关的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
然后在application.properties文件中配置Redis相关属性
#配置Redis服务器属性
spring.redis.host=192.168.115.133
spring.redis.port=6379
#配置连接超时时间(毫秒)
spring.redis.timeout=3000
#配置连接池属性
spring.redis.jedis.pool.max-active=20
spring.redis.jedis.pool.max-idle=20
spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-wait=3000
#缓存名称,一般会作为缓存在业务上的分类,以key的前缀出现(userCache::)
spring.cache.cache-names=userCache
#禁用缓存前缀
#spring.cache.redis.use-key-prefix=false
#缓存超时时间
spring.cache.redis.time-to-live=120000
具体实现
用户实体类
@Setter
@Getter
@ToString
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
}
接口
public interface CacheService {
User saveUser(User user);
User getUser(Integer id);
User updateUser(User user);
Integer removeUser(Integer id);
}
接口实现类
@Service
public class CacheServiceImpl implements CacheService {
// 为了简化功能,用一个集合代替数据库
private Map<Integer, User> db = new ConcurrentHashMap<>();
@Override
@CachePut(value = "userCache", key = "'user:' + #result.id")
public User saveUser(User user) {
// 保存user信息 省略保存数据库的过程
db.put(user.getId(), user);
return user;
}
@Override
@Cacheable(value = "userCache", key = "'user:' + #id", unless = "#result == null")
public User getUser(Integer id) {
System.out.println("没有命中缓存,进入业务方法了");
return db.get(id);
}
@Override
@CachePut(value = "userCache", key = "'user:' + #result.id", condition = "#result != null")
public User updateUser(User user) {
// 调用getUser方法,user存在才会更新
// 基于SpringAOP原理,同类中的方法调用会导致切面失效,因此这里会使getUser的缓存注解会失效
User u = this.getUser(user.getId());
if (u == null) {
return null;
}
db.put(user.getId(), u);
return user;
}
@Override
@CacheEvict(value = "userCache", key = "'user:' + #id", beforeInvocation = true)
public Integer removeUser(Integer id) {
db.remove(id);
return 1;
}
}
缓存注解说明
在CacheServiceImpl实现类中,分别定义了对于用户信息的增删改查四个方法,其中涉及到了三类缓存注解。
@CachePut
表示将方法结果返回放到缓存中。其中value属性的值与在application.properties中配置的缓存名称对应,会以key的前缀出现,key属性的配置用到了Spring EL表达式,#result.id代表返回值的id属性的值,#id代表入参id的值。
@Cacheable
表示先从缓存中通过定义的键查询,如何可以查到则直接返回,否则执行方法具体内容返回数据,并将结果返回,unless = "#result == null"代表如果结果为null则不缓存,等同于condition = "#result != null"。
@CacheEvict
表示通过定义的键移除缓存,beforeInvocation属性代表在方法之前或者之后移除缓存,这里定义为true,代表在方法执行前移除缓存,默认为false。
测试结果
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisDemoApplicationTests {
@Autowired
private CacheService cacheService;
@Test
public void test() {
saveUser();
getUser();
updateUser();
removeUser();
}
private void saveUser() {
User u = new User();
u.setId(1);
u.setName("张三");
u.setAge(25);
User user = cacheService.saveUser(u);
System.out.println("【save】" + user);
}
private void getUser() {
User user = cacheService.getUser(1);
System.out.println("【get】" + user);
}
private void updateUser() {
User u = cacheService.getUser(1);
u.setName("李四");
u.setAge(30);
User user = cacheService.updateUser(u);
System.out.println("【update】" + user);
}
private void removeUser() {
Integer r = cacheService.removeUser(1);
System.out.println("【remove】" + r);
}
}
test()方法先后执行了saveUser()、getUser()、updateUser()、removeUser()四个过程,可以在每一步设置断点,然后通过Redis客户端观察缓存真是的更新情况。
saveUser
首先执行saveUser,通过Redis客户端可以看到,user的缓存信息已经成功保存。
127.0.0.1:6379> keys *
1) "userCache::user:1"
127.0.0.1:6379> get userCache::user:1
"\xac\xed\x00\x05sr\x00\x1ecom.hujy.redisdemo.entity.User\xc3a\xa1\xe5\xf1\xa2B\x86\x02\x00\x03L\x00\x03aget\x00\x13Ljava/lang/Integer;L\x00\x02idq\x00~\x00\x01L\x00\x04namet\x00\x12Ljava/lang/String;xpsr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x00\x19sq\x00~\x00\x04\x00\x00\x00\x01t\x00\x06\xe5\xbc\xa0\xe4\xb8\x89"
getUser
继续执行完getUser方法,此时的控制台信息:
【save】User(id=1, name=张三, age=25)
【get】User(id=1, name=张三, age=25)
可以正确的返回我们期望的结果,而且发现方法内的打印信息并没有执行,说明已经命中了缓存。
updateUser
接着执行updateUser,红色部分是updateUser方法打印的信息,因为在updateUser方法内部又调用了getUser方法,基于SpringAOP原理,同类中的方法调用会导致切面失效,因此这里会使getUser的缓存注解会失效,进入了方法内部,最后可以看到缓存已经被更新。
控制台信息:
【save】User(id=1, name=张三, age=25)
【get】User(id=1, name=张三, age=25)
没有命中缓存,进入业务方法了
【update】User(id=1, name=李四, age=30)
【get】User(id=1, name=李四, age=30)
removeUser
最后执行了removeUser方法,通过Redis客户端可以看到缓存信息已经被删除了。
127.0.0.1:6379> get userCache::user:1
(nil)
127.0.0.1:6379> keys *
(empty list or set)
完整的控制台信息:
【save】User(id=1, name=张三, age=25)
【get】User(id=1, name=张三, age=25)
没有命中缓存,进入业务方法了
【update】User(id=1, name=李四, age=30)
【get】User(id=1, name=李四, age=30)
【remove】1
完整代码地址:https://github.com/hjy0319/redis-demo