Spring boot redis的使用
实际的业务中随着业务量的增大,访问量也是慢慢跟着变大,尤其是到达一定的临界点的时候服务器将会不堪其重造成一种假死的状态给用户以“崩溃”感觉,严重的时候甚至可能直接宕机,而我们传统的做法就是:1.应用程序方面采用多节点的负载均衡;2.数据库方面采用主从读写分离、分库、分表等,而现在呢又多了一种方式采用nosql产品来做cache层来分离高并发的压力,也确实起到了很好的效果,市场上已经有很多nosql产品,而本章我们将介绍其中的一种redis。
1. 使用前的准备工作
1.1 下载redis并安装-->网上有很多教程,也很简单,这里就不多介绍了
1.2 引入依赖
1.3 进行基本的参数配置
2. redis的基本使用
2.1 编写redis的基本配置类,代码如下-->详情可看代码中的注释(@EnableCaching表示启动注解):
简要说明:1、使用@EnableCaching启用Cache注解支持;
2、实现CachingConfigurer,然后注入需要的cacheManager和keyGenerator;从spring4开始默认的keyGenerator是SimpleKeyGenerator--》缓存key生产策略;
package com.zxl.examples.catche;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Administrator on 2017/7/25.
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
//缓存key生产策略
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
//注册RedisCacheManager:缓存管理器
//
// 为了实现cache注解支持过期时间,提供以下两种方法
// 1.修改CacheManager设置对应缓存名称的过期时间
// 2.扩展CacheManager实现参数化设置过期时间:如@Cacheable(value="userCache#120",key="'user:'+#username",unless = "#result==null")
@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//设置缓存过期时间
//rcm.setDefaultExpiration(60);//秒
//指定缓存名称的过期时间
Map expiresMap=new HashMap();
expiresMap.put("userCache",60L);//单位秒
rcm.setExpires(expiresMap);
return rcm;
}
// @SuppressWarnings("rawtypes")
// @Bean
// public CacheManager cacheManager(RedisTemplate redisTemplate) {
// RedisCacheManager rcm = new RedisCacheManagerExtend(redisTemplate);
// //设置缓存过期时间
// //rcm.setDefaultExpiration(60);//秒
// return rcm;
// }
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 使用String格式序列化缓存键
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
package com.zxl.examples.service;
import com.zxl.examples.catche.customannotation.UserSaveCache;
import com.zxl.examples.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Created by Administrator on 2017/7/24.
*/
@Service("userSerivce")
public class UserSerivceImpl {
@Autowired
UserRepository userRepository;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate redisTemplate;
//unless-->用于否决缓存更新的,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了
@Cacheable(value="userCache",key="'user:'+#username",unless = "#result==null")
public User getUserByUsername(String username){
User user = null;
List userlist = userRepository.findByUsername(username);
if(userlist!=null && userlist.size()>0){
user = userlist.get(0);
}
return user;
}
// @Cacheable(value="userCache#120",key="'user:'+#username",unless = "#result==null")
// public User getUserByUsername(String username){
// User user = null;
// List userlist = userRepository.findByUsername(username);
// if(userlist!=null && userlist.size()>0){
// user = userlist.get(0);
// }
// return user;
// }
//allEntries-->是否移除所有数据
//beforeInvocation-->是调用方法之前移除/还是调用之后移除
@CacheEvict(value = "userCache",key="'user:'+#user.username")
public void delUserById(User user){
userRepository.delete(user);
}
public String setUserInRedis(){
stringRedisTemplate.opsForValue().set("abc","123",60L, TimeUnit.SECONDS);
return stringRedisTemplate.opsForValue().get("abc");
// redisTemplate.opsForList();//可直接放入实现序列化的pojo
}
public void delUserInRedis(){
stringRedisTemplate.delete("abc");
}
//condition-->满足缓存条件的数据才会放入缓存,condition在调用方法之前和之后都会判断
@CachePut(value="userCache",key = "#user.username",condition = "#user.username<='100'")
public User save(User user){
userRepository.save(user);
return user;
}
@Caching(
put={
@CachePut(value = "userCache", key = "'user:'+#user.id"),
@CachePut(value = "userCache", key = "'user:'+#user.username")
}
)
public User addUser(User user){
userRepository.save(user);
return user;
}
@UserSaveCache
public User addUser2(User user){
userRepository.save(user);
return user;
}
@Cacheable(value="userCache",key="'user:'+#username",condition = "#root.target.canCache()",unless = "#result==null")
public User getUserByUsername2(String username){
User user = null;
List userlist = userRepository.findByUsername(username);
if(userlist!=null && userlist.size()>0){
user = userlist.get(0);
}
return user;
}
@Cacheable(value="userCache",key="'user:'+#username",condition = "#root.target.notCache()")
public User getUserByUsername3(String username){
User user = null;
List userlist = userRepository.findByUsername(username);
if(userlist!=null && userlist.size()>0){
user = userlist.get(0);
}
return user;
}
public boolean canCache(){
return true;
}
public boolean notCache(){
return false;
}
}
package com.zxl.examples.controller;
import com.zxl.examples.controller.common.ResultBean;
import com.zxl.examples.controller.common.SuccessBean;
import com.zxl.examples.entity.User;
import com.zxl.examples.service.UserRepository;
import com.zxl.examples.service.UserSerivceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2017/7/24.
*/
@RestController
public class UserController {
@Autowired
UserRepository userRepository;
@Autowired
UserSerivceImpl userSerivce;
@GetMapping("/users/moreparam18/{username}")
public User getUserByUsername(@PathVariable String username){
//页数从0开始算,比如第一页应传page=0
return userSerivce.getUserByUsername(username);
}
@DeleteMapping("/users/del/{id}")
public void delUserById12(@PathVariable Long id){
User user = userRepository.findOne(id);
if(user !=null){
userSerivce.delUserById(user);
}
}
@GetMapping("/users/moreparam19")
public String setUserInRedis(){
//页数从0开始算,比如第一页应传page=0
return userSerivce.setUserInRedis();
}
@GetMapping("/users/moreparam20")
public void delUserInRedis(){
//页数从0开始算,比如第一页应传page=0
userSerivce.delUserInRedis();
}
@PostMapping("/users/moreparam21/{username}")
public User save(@PathVariable String username){
//页数从0开始算,比如第一页应传page=0
User user = new User();
user.setUsername(username);
user.setPassword("123456");
user.setName(username);
userSerivce.save(user);
return user;
}
@PostMapping("/users/moreparam22/{username}")
public User addUser(@PathVariable String username){
//页数从0开始算,比如第一页应传page=0
User user = new User();
user.setUsername(username);
user.setPassword("123456");
user.setName(username);
userSerivce.addUser(user);
return user;
}
@PostMapping("/users/moreparam23/{username}")
public User addUser2(@PathVariable String username){
//页数从0开始算,比如第一页应传page=0
User user = new User();
user.setUsername(username);
user.setPassword("123456");
user.setName(username);
userSerivce.addUser2(user);
return user;
}
@GetMapping("/users/moreparam24/{username}")
public User getUserByUsername2(@PathVariable String username){
//页数从0开始算,比如第一页应传page=0
return userSerivce.getUserByUsername2(username);
}
@GetMapping("/users/moreparam25/{username}")
public User getUserByUsername3(@PathVariable String username){
//页数从0开始算,比如第一页应传page=0
return userSerivce.getUserByUsername3(username);
}
}
名字 | 位置 | 描述 | 示例 |
methodName | root对象 | 当前被调用的方法名 | #root.methodName |
method | root对象 | 当前被调用的方法 | #root.method.name |
target | root对象 | 当前被调用的目标对象 | #root.target |
targetClass | root对象 | 当前被调用的目标对象类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root对象 | 当前方法调用使用的缓存列表(如@Cacheable(value={"cache1", "cache2"})),则有两个cache | #root.caches[0].name |
argument name | 执行上下文 | 当前被调用的方法的参数,如findById(Long id),我们可以通过#id拿到参数 | #user.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless’,'cache evict'的beforeInvocation=false) | #result |