SpringBoot + Redis实现数据缓存及缓存注解的用法总结

一.@Cacheable,@CacheEvict,@CachePut,@CacheConfig等注解及其属性的用法

1.1 @Cacheable

@Cacheable的属性的意义

  • cacheNames:指定缓存的名称
  • key:定义组成的key值,如果不定义,则使用全部的参数计算一个key值。可以使用spring El表达式
  • keyGenerator:定义key生成的类,和key的不能同时存在
  • sync:如果设置sync=true:a. 如果缓存中没有数据,多个线程同时访问这个方法,则只有一个方法会执行到方法,其它方法需要等待; b. 如果缓存中已经有数据,则多个线程可以同时从缓存中获取数据
  • condition和unless 只满足特定条件才进行缓存:

       1. condition: 在执行方法前,condition的值为true,则缓存数据
       2.unless :在执行方法后,判断unless ,如果值为true,则不缓存数据
       3.conditon和unless可以同时使用,则此时只缓存同时满足两者的记录

1.2 @CacheEvict

删除缓存

  • allEntries = true: 清空缓存book1里的所有值
  • allEntries = false: 默认值,此时只删除key对应的值

1.3 @CachePut

每次执行都会执行方法,无论缓存里是否有值,同时使用新的返回值的替换缓存中的值。这里不同@Cacheable:@Cacheable如果缓存没有值,从则执行方法并缓存数据,如果缓存有值,则从缓存中获取值

1.4 @CacheConfig

@CacheConfig: 类级别的注解:如果我们在此注解中定义cacheNames,则此类中的所有方法上 @Cacheable的cacheNames默认都是此值。当然@Cacheable也可以重定义cacheNames的值

二.写个使用SpringBoot + Redis实现数据缓存的工程

2.1 添加Maven依赖


	4.0.0

	com.weichai
	SpringCache
	0.0.1-SNAPSHOT
	jar

	SpringCache
	http://maven.apache.org

	
		UTF-8
		UTF-8
		1.8
	

	
		
			org.springframework.boot
			spring-boot-starter-web
			1.5.18.RELEASE
		
		
		
			org.mybatis.spring.boot
			mybatis-spring-boot-starter
			1.3.0
		
		
			mysql
			mysql-connector-java
			6.0.5
		
		
			org.springframework.boot
			spring-boot-starter-cache
			1.5.18.RELEASE
		
		
			org.springframework.boot
			spring-boot-starter-data-redis
			1.5.18.RELEASE
		
		
			com.alibaba
			fastjson
			1.2.24
		
		
			org.apache.commons
			commons-lang3
			3.8
		
		
			com.google.guava
			guava
			27.0-jre
		
		
			org.apache.commons
			commons-collections4
			4.0
		
		
			junit
			junit
			3.8.1
			test
		
	

2.2 application.properties属性文件

spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6380
spring.redis.password=123456
spring.redis.pool.max-active=10
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=10
spring.redis.pool.min-idle=0
spring.redis.timeout=2000
mybatis.mapper-locations=classpath:mappings/modules/user/*.xml
#spring.cache.cache-names=user
spring.cache.type=redis
server.port=8090

2.3 Redis缓存配置类

package com.weichai.SpringCache.config;

import org.springframework.beans.factory.annotation.Value;
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.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


/**
 * Redis缓存配置类
 * 初始化redis做数据缓存
 * @author linhaiy
 * @date 2019.03.05
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
	
	@Value("${spring.redis.host}")
	private String host;
	@Value("${spring.redis.port}")
	private int port;
    @Value("${spring.redis.timeout}")
	private int timeout;
    
    private static int OverTime = 120;
    
  /**
   * 自定义缓存key生成策略
   */
  @Bean
  public KeyGenerator keyGenerator() {
      return new KeyGenerator(){
          public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
              StringBuffer sb = new StringBuffer();
              sb.append(target.getClass().getName());
              sb.append(method.getName());
              for(Object obj:params){
                  sb.append(obj.toString());
              }
              return sb.toString();
          }
      };
  }

    /**
     * 缓存管理器(注意:此方法在SpringBoot2.0以下版本才有效,2.0以后得版本参照
     * https://blog.csdn.net/Mirt_/article/details/80934312 来写)
     * @param redisTemplate
     * @return
     */
    @Bean 
	public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
		RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
		cacheManager.setDefaultExpiration(OverTime); // 设置缓存过期时间
		return cacheManager;
	}
    
	
    /**
     * RedisTemplate序列化器之GenericJackson2JsonRedisSerializer
     * @return
     */
	@Bean(name = "springSessionDefaultRedisSerializer")
	public GenericJackson2JsonRedisSerializer getGenericJackson2JsonRedisSerializer() {
		return new GenericJackson2JsonRedisSerializer();
	}

	/**
	 * 设置RedisTemplate的序列化器。 
	 * @param connectionFactory
	 * @return
	 */
	@Bean
	public RedisTemplate getRedisTemplate(JedisConnectionFactory connectionFactory) {
		RedisTemplate redisTemplate = new RedisTemplate();
		redisTemplate.setConnectionFactory(connectionFactory);
		redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
		StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
		redisTemplate.setKeySerializer(stringRedisSerializer);
		redisTemplate.setHashKeySerializer(stringRedisSerializer);
		return redisTemplate;
	}
	
}

2.4 有缓存功能的接口实现

package com.weichai.SpringCache.entity;

import java.io.Serializable;

public class User implements Serializable {

	private String id;
	private String userName;
	private String userPwd;
	private Integer age;
	private String address;

	public User(String id, String userName, String userPwd, Integer age, String address) {
		super();
		this.id = id;
		this.userName = userName;
		this.userPwd = userPwd;
		this.age = age;
		this.address = address;
	}

	public User() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getUserPwd() {
		return userPwd;
	}
	public void setUserPwd(String userPwd) {
		this.userPwd = userPwd;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", userName=" + userName + ", userPwd=" + userPwd + ", age=" + age + ", address="
				+ address + "]";
	}
	
	
}
package com.weichai.SpringCache.entity;

import java.io.Serializable;
/**
 * 数据接口返回结果
 * @author linhaiy
 * @date 2019.03.01
 * @param 
 */
public class ResponseResult implements Serializable {

	public static final int STATE_ERROR=-1;
    public static final int STATE_OK=1;
	private static final long serialVersionUID = 2158690201147047546L;
	private int status;           //返回状态
	private String message;       //返回信息
	private T data;               //返回数据
	public ResponseResult() {
		super();
		// TODO Auto-generated constructor stub
	}
	public ResponseResult(int status, String message, T data) {
		super();
		this.status = status;
		this.message = message;
		this.data = data;
	}
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((data == null) ? 0 : data.hashCode());
		result = prime * result + ((message == null) ? 0 : message.hashCode());
		result = prime * result + status;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ResponseResult other = (ResponseResult) obj;
		if (data == null) {
			if (other.data != null)
				return false;
		} else if (!data.equals(other.data))
			return false;
		if (message == null) {
			if (other.message != null)
				return false;
		} else if (!message.equals(other.message))
			return false;
		if (status != other.status)
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "ResponseResult [status=" + status + ", message=" + message + ", data=" + data + "]";
	}
	
	
}



	
		a.id as "id",
		a.userName as "userName",
		a.userPwd as
		"userPwd",
		a.age as "age",
		a.address as "address"
	

	
	

	
	

	
	

	
	
		INSERT INTO user(id,userName,userPwd,age,address)
		VALUES
		(#{id},#{userName},#{userPwd},#{age},#{address})
	

	
	
		DELETE FROM user WHERE id = #{id}
	

	
	
		UPDATE user SET userPwd = #{userPwd} WHERE id = #{id}
	
package com.weichai.SpringCache.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.weichai.SpringCache.entity.User;

@Mapper
public interface UserDao {

	public List findList();
	
	public User findById(String id);
	
	public void AddUser(User user);
	
	public void deleteUser(String id);

	public void updatePwdById(User user);
}
package com.weichai.SpringCache.service;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.weichai.SpringCache.dao.UserDao;
import com.weichai.SpringCache.entity.User;

/**
 * 缓存机制是作用到Service层的,
 * 而dao或者repository层缓存用注解,用key的话它会认定为null。
 * 要用KeyGenerator来提前生成key的生成策略
 * @author linhaiy
 *
 */
@Service
@CacheConfig(cacheNames = "user")
public class UserService {
	
	@Resource
	private UserDao userDao;
	
	@Cacheable(value="user")
    public List findList(){
    	return userDao.findList();
    }
	
	@Cacheable(cacheNames="user",key ="#id")
	public User findById(String id) {
		return userDao.findById(id);
	}
	
	/**
	 * acheNames 设置缓存的值 
     * key:指定缓存的key,这是指参数id值。 key可以使用spEl表达式,也可以是指定对象的成员变量
	 * @param user
	 */
	@CachePut(cacheNames="user",key = "#user.id")
	public void AddUser(User user) {
		userDao.AddUser(user);
	}
	
    //如果指定为 true,则方法调用后将立即清空所有缓存
    @CacheEvict(key ="#id",allEntries=true)
	public void deleteUser(String id) {
		userDao.deleteUser(id);
	}
	
    @CachePut(cacheNames="user",key = "#user.id")
	public void updatePwdById(User user) {
		userDao.updatePwdById(user);
	}
	
    /**
     * 条件缓存:
     * 只有满足condition的请求才可以进行缓存,如果不满足条件,则跟方法没有@Cacheable注解的方法一样
     * 如下面只有id < 3才进行缓存
     * @param id
     * @return
     */
	@Cacheable(cacheNames = "user", condition = "T(java.lang.Integer).parseInt(#id) < 3 ")
	public User queryUserByIdCondition(String id) {
		return userDao.findById(id);
	}

}
package com.weichai.SpringCache.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.weichai.SpringCache.entity.ResponseResult;
import com.weichai.SpringCache.entity.User;
import com.weichai.SpringCache.service.UserService;
import com.weichai.SpringCache.util.StringUtils;

/**
 * 用户缓存测试类
 * @author linhaiy
 * @date 2019.03.05
 */
@RestController
@RequestMapping(value = "/userCache")
public class UserController {

	@Autowired
    private UserService userService;
	
	@RequestMapping("/findList")
	@ResponseBody
    public JSONObject findList(HttpServletRequest request){
		JSONObject rr = new JSONObject();
		List list = userService.findList();
		if(list !=null && list.size() >0) {
			rr.put("state","0");
	        rr.put("msg","success");
            rr.put("data", list);
		}
		return rr;
	}
	
	@RequestMapping("/findById")
	@ResponseBody
    public ResponseResult findById(@RequestParam String id){
		ResponseResult resData = new ResponseResult();
		User user = userService.findById(id);
		resData.setStatus(0);
		resData.setMessage("成功获取数据");
		resData.setData(user);
		return resData;
	}
	
	@RequestMapping(value = "AddUser",method= RequestMethod.POST)
    @ResponseBody
	public JSONObject AddUser(User user){
		JSONObject rr = new JSONObject();
		try {
			if(user !=null) {
				userService.AddUser(user);
				rr.put("state","0");
                rr.put("msg","success");
			}else {
				rr.put("state","2");
                rr.put("msg","参数错误");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
            rr.put("state","2");
            rr.put("msg","保存用户信息失败");
			e.printStackTrace();
		}
		return rr;
	}
	
	@RequestMapping(value = "deleteUser",method= RequestMethod.POST)
    @ResponseBody
    public JSONObject deleteUser(@RequestParam String id){
		JSONObject rr = new JSONObject();
		try {
			if(StringUtils.isNotBlank(id)) {
				userService.deleteUser(id);
				rr.put("state","0");
			    rr.put("msg","用户信息删除成功");
			}else {
				rr.put("state","2");
                rr.put("msg","参数输入错误");
			}
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			rr.put("state","2");
            rr.put("msg","用户操作错误");
		}
		return rr;
	}
	
	@RequestMapping(value = "updatePwdById",method= RequestMethod.POST)
    @ResponseBody
    public JSONObject updatePwdById(User user){
		JSONObject rr = new JSONObject();
		try {
			if(user !=null) {
				if(StringUtils.isNotBlank(user.getUserPwd())) {
					userService.updatePwdById(user);
					rr.put("state","0");
                    rr.put("msg","用户密码修改成功");
				}else {
					rr.put("state","2");
                    rr.put("msg","参数错误");
				}
			}else {
				rr.put("state","2");
                rr.put("msg","没有修改数据");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			rr.put("state","2");
            rr.put("msg","用户操作错误");
            e.printStackTrace();
		}
		return rr;
	}
}

2.5 项目启动

package com.weichai.SpringCache;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * SpringBoot启动诶
 * @EnableCaching: 启动缓存
 * @author linhaiy
 * @date 2019.03.05
 */
@SpringBootApplication
@EnableScheduling
@EnableCaching
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class, args);
    }
}

2.6 部分接口缓存功能测试

SpringBoot + Redis实现数据缓存及缓存注解的用法总结_第1张图片

Redis服务器出现的缓存数据

SpringBoot + Redis实现数据缓存及缓存注解的用法总结_第2张图片

修改之前的一条数据记录

SpringBoot + Redis实现数据缓存及缓存注解的用法总结_第3张图片

SpringBoot + Redis实现数据缓存及缓存注解的用法总结_第4张图片

SpringBoot + Redis实现数据缓存及缓存注解的用法总结_第5张图片

SpringBoot + Redis实现数据缓存及缓存注解的用法总结_第6张图片

其他接口就不测试了

 

 

 

你可能感兴趣的:(NoSQL学习笔记)