当前位置:   article > 正文

Springboot——整合Redis和cache缓存_springboot redis cache

springboot redis cache

前言

实际开发中,针对请求量大的数据并且频繁请求的数据信息,在不断的对数据库mysql、oracle等操作下,造成额外多的性能开销,同时获取信息会很慢。

为了减少频繁查询,造成响应时间大、服务器压力大的问题,可以采取设置缓存。

Spring Cache

SpringCacheSpring 3.1 版本发布出来的,对使用缓存进行了封装和抽象,通过在方法上使用annotation注解就能拿到缓存信息。

对于Redis缓存,SpringCache只支持String类型,其他Hash、List、Set、ZSet都不支持。

案例达到目的

查找、删除、修改某项数据后,Redis缓存中的对应数据也做变更。

之前不采取配置方式,只类似如下逻辑方式进行操作(伪代码):

@RequestMapping("/xxxx)
User getUser(String uid){
	// 查询mysql
	// 向redis中写入相关数据
	// 回执
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

此时采取配置方式实现数据的缓存保存,避免额外的代码量。

依赖引入

<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>1.3.2</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<!-- <version>5.0.4</version> -->
</dependency>
<!-- swagger -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.4.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.4.0</version>
</dependency>
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>swagger-bootstrap-ui</artifactId>
    <version>1.9.6</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

配置文件

由于使用Spring 自带的cache,将查询到的数据信息保存至redis中,此处需要做两类配置:

redis保存对象、json等信息的编码配置类。
cache保存缓存信息等配置类。

  • yml 链接参数
server:
  port: 80

  
# 配置redis以及cache
spring:
  redis:
    host: 192.168.99.100
    port: 10000
    password: xiangjiao
    timeout: 10000 #连接超时时间
    #database: 1
    jedis: ## jedis配置
      pool: ## 连接池配置
        max-idle: 8 ## 最大空闲连接数
        max-active: 8 ## 最大连接数
        max-wait: 3000 ## 最大阻塞等待时间
        min-idle: 0 ## 最小空闲连接数
        
  datasource:
    url: jdbc:mysql://192.168.99.100:3306/redis_cache?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    
  profiles.active: dev
    
## mapper 配置
logging.level.cn.linkpower.dao: debug
## mybatis 配置
mybatis:
  ## 驼峰命名匹配
  configuration:
    map-underscore-to-camel-case: true
  type-aliases-package: cn.linkpower.dao
  ## 扫描mapper文件
  mapper-locations:
    - classpath:mapper/*.xml   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • java配置类的编写
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
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.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableCaching  // 开启缓存
public class RedisConfig {
	
	/**
	 * 重写Redis序列化定义方式,采取json方式————避免json格式乱码
	 * @param factory
	 * @return
	 */
	@Bean
	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
		redisTemplate.setConnectionFactory(factory);
		// 创建json序列化对象
		GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
		// 设置key序列化String
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		// 设置value序列化 json
		redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
		// 设置hash key序列化String
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		// 设置hash value 序列化json
		redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
		
		// 初始化redis完成序列化的方法
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}
	
	/**
	 * 缓存配置
	 * @param factory
	 * @return
	 */
	@Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration cacheConfiguration =
        		RedisCacheConfiguration.defaultCacheConfig()
        				//设置缓存默认超时时间  30分钟
        				//.entryTtl(Duration.ofMillis(30))
                        .disableCachingNullValues()
                        // 设置key序列化  
                        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();

    }
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • swagger 在线接口文档配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2 //启动Swagger
public class SwaggerConfig {
	
	/**
	 * swagger 核心类
	 * @return
	 */
	@Bean
	public Docket createRestApi1(Environment environment) {
		// 适用环境
		Profiles profiles = Profiles.of("dev", "test");
		boolean flag = environment.acceptsProfiles(profiles);
		
		return new Docket(DocumentationType.SWAGGER_2)
				.groupName("AAA")
				.apiInfo(apiInfo())
				.enable(flag)//enable是否启动swagger,如果为false,则Swagger不能在浏览器中访问
				.select()
				//RequestHandlerSelectors, 配置要扫描接口的方式
                //basePackage()扫描全部
                //any()扫描全部
                //none()不扫描
                //withClassAnnotation()扫描方法上的注解
				.apis(RequestHandlerSelectors.basePackage("cn.linkpower"))
				//path() 过滤什么路径
				.paths(PathSelectors.any())
				.build();
	}
	
	/**
	 * 分组显示
	 * @return
	 */
	@Bean
	public Docket createRestApi2(Environment environment) {
		// 适用环境
		Profiles profiles = Profiles.of("dev", "test");
		boolean flag = environment.acceptsProfiles(profiles);
				
		return new Docket(DocumentationType.SWAGGER_2)
				.groupName("BBB")
				.apiInfo(apiInfo())
				.enable(flag)//enable是否启动swagger,如果为false,则Swagger不能在浏览器中访问
				.select()
				//RequestHandlerSelectors, 配置要扫描接口的方式
                //basePackage()扫描全部
                //any()扫描全部
                //none()不扫描
                //withClassAnnotation()扫描方法上的注解
				.apis(RequestHandlerSelectors.basePackage("cn.linkpower"))
				//path() 过滤什么路径
				.paths(PathSelectors.any())
				.build();
	}
	
	private ApiInfo apiInfo() {
		return new ApiInfoBuilder()
				// 标题
				.title("专注写bug , swagger测试")
				// 创建人基础信息
				.contact(new Contact("专注写bugs", "localhost:80", "123@qq.com"))
				// 版本信息
				.version("1.0.0")
				.description("swagger 测试代码")
				.build();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

配置后的文件目录

在这里插入图片描述

编写测试类等基本代码

  • sql
    新建数据库,导入sql创建表格,添加数据。
CREATE TABLE `user` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `userName` varchar(32) NOT NULL,
  `passWord` varchar(50) NOT NULL,
  `createTimes` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 接口
    写一个测试使用的接口
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.linkpower.service.UserService;
import cn.linkpower.vo.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;

@RestController
@Api("用户测试类")
public class UserController {
	
	Logger log = LoggerFactory.getLogger(UserController.class);
	
	@Autowired
	private UserService userServiceImpl;
	
	@GetMapping("/getuser/{id}")
	@ApiOperation(value = "获取用户信息",notes = "queryUser")
	@ApiImplicitParam(name = "id", value = "用户id", paramType = "path", required = true, dataType = "String")
	public User queryUser(@PathVariable(value = "id") String id) {
		log.info("----queryUser---id---{}",String.valueOf(id));
		return userServiceImpl.queryUserById(Integer.parseInt(id));
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • service
    编写指定的业务类,实现调用mapper和设置缓存
import cn.linkpower.vo.User;

public interface UserService {
	
	/**
	 * 根据id查询用户信息
	 * @param id
	 * @return
	 */
	User queryUserById(Integer id);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import cn.linkpower.dao.UserMapper;
import cn.linkpower.vo.User;

@Service
//@CacheConfig(cacheNames = {"user"}) //提取注解公共属性
public class UserServiceImpl implements UserService {
	
	Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
	
	@Autowired
	private UserMapper userMapper;
	
	@Override
	@Cacheable(value = "userCache", key = "#id")
	public User queryUserById(Integer id) {
		log.error("----查询数据库----");
		return userMapper.queryUserById(id);
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 数据库User表对应User.java
    注意一定要求序列化!
import java.io.Serializable;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("用户实体类")
public class User implements Serializable {
	private static final long serialVersionUID = 3526560195700752585L;
	@ApiModelProperty("用户主键")
	private Integer id;
	@ApiModelProperty("用户名")
	private String userName;
	@ApiModelProperty("用户密码")
	private String passWord;
	@ApiModelProperty("创建日期")
	private Long createTimes;
	@Override
	public String toString() {
		return "User [id=" + id + ", userName=" + userName + ", passWord=" + passWord + ", createTimes=" + createTimes
				+ "]";
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • mapper
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import cn.linkpower.vo.User;

@Mapper
public interface UserMapper {
	/**
	 * 根据id查询用户信息
	 * @param id
	 * @return
	 */
	@Select("select id,userName,passWord,createTimes from user where id = #{id}")
	User queryUserById(Integer id);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

初步测试,查看数据是否能被添加至Redis缓存

此处配置了在线接口文档,就从接口文档中进行请求测试:

http://localhost/doc.html
在这里插入图片描述
在这里插入图片描述

请求接口链接,查看后台日志输出:
在这里插入图片描述
在这里插入图片描述

由于初始Redis中并未存在缓存信息,所以先会从数据库中查询信息并添加至Redis中,在之后的请求操作中,由于此时Redis中已存在指定的缓存信息,则直接从Redis中返回对应信息。

cache注解测试和详解

@Cacheable 注解

在这里插入图片描述
该注解用于需要进行缓存操作的方法(一般是service接口)。其中包含上述的几个配置项。

  • String[] cacheNames() default {}

缓存操作,指定数据对应的名称,可以多个。

  • String[] value() default {}

cacheNames的别名。

  • String key() default ""

Spring Expression Language(SpEL)表达式,用于动态计算密钥。

Spel 表达式默认提供了专用的上下文求值,比如:
#root.method java.lang.reflect.Method方法、
#root.target 目标对象、
#root.caches 受影响的缓存,
#root.methodName 方法名、
#root.targetClass 目标类
修改业务代码,查看缓存数据保存格式:

@Autowired
	private UserMapper userMapper;
	
	@Override
	@Cacheable( key = "#root.method")
	public User queryUserById(Integer userId) {
		log.error("----查询数据库----");
		return userMapper.queryUserById(userId);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

此处修改为#root.method,请求接口,查看redis中保存的数据格式:
在这里插入图片描述
在这里插入图片描述
注意!!!
但是使用#root.method#root.target#root.caches等会出现如下问题:

当参数信息变更,Redis缓存中的信息不会更改!!!导致缓存数据读取是错误的。
在这里插入图片描述

该项参数信息可以为空,如果编写必须按照spel语法指定。其次也能按照接受参数指定:

@Override
	@Cacheable( key = "#userId")
	public User queryUserById(Integer userId) {
		log.error("----查询数据库----");
		return userMapper.queryUserById(userId);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

必须保证key中的名称值和方法中对应参数的名称保持一致,否则报错!
在这里插入图片描述

在这里插入图片描述

  • String condition() default ""
    缓存条件。当满足条件才能进行缓存等操作。
    可以为空,使用 SpEL 编写,返回 true 或者 false,
    只有为 true 才进行缓存/清除缓存
    例如:
	@Override
	@Cacheable( key = "#userId",condition = "#userId>1")
	public User queryUserById2(Integer userId) {
		log.error("----查询数据库----");
		return userMapper.queryUserById(userId);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

不满足条件查询:
在这里插入图片描述
满足条件查询:
在这里插入图片描述

  • String unless() default ""
    表示不满足指定的条件时,才进行缓存操作。
    当条件为true时,就不会缓存。

@CacheConfig注解

这项注解信息表示某个类中很多缓存操作时,名称的汇总。

@CacheConfig(cacheNames = {“user”}) //提取注解公共属性

在这里插入图片描述

@CachePut 注解

表示缓存的更新操作。如下所示:

控制层:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.linkpower.service.UserService;
import cn.linkpower.vo.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;

@RestController
@Api("用户测试类")
public class UserController {
	
	Logger log = LoggerFactory.getLogger(UserController.class);
	
	@Autowired
	private UserService userServiceImpl;
	
	@GetMapping("/getuser/{id}")
	@ApiOperation(value = "获取用户信息",notes = "queryUser")
	@ApiImplicitParam(name = "id", value = "用户id", paramType = "path", required = true, dataType = "String")
	public User queryUser(@PathVariable(value = "id") String id) {
		log.info("----queryUser---id---{}",String.valueOf(id));
		return userServiceImpl.queryUserById1(Integer.parseInt(id));
	}
	
	@PostMapping("/updateUser")
	@ApiOperation(value = "修改用户信息",notes = "updateUser")
	//@ApiImplicitParam(name = "user", value = "用户信息", paramType = "body", required = true, dataType = "cn.linkpower.vo.User")
	public User updateUser( @RequestBody User user) {
		
		return userServiceImpl.updateUser(user);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

业务层:

@Override
@Cacheable( key = "#userId")
public User queryUserById1(Integer userId) {
	log.error("----查询数据库----");
	return userMapper.queryUserById(userId);
}

@Override
@CachePut(key = "#user.id")
public User updateUser(User user) {
	log.error("----更新数据库----");
	userMapper.updateUser(user);
	log.info("id:{}",user.getId());
	return userMapper.queryUserById(user.getId()); 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

dao层:

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import cn.linkpower.vo.User;

@Mapper
public interface UserMapper {
	/**
	 * 根据id查询用户信息
	 * @param id
	 * @return
	 */
	@Select("select id,userName,passWord,createTimes from user where id = #{id}")
	User queryUserById(Integer id);
	
	void updateUser(User user);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
<update id="updateUser" parameterType="cn.linkpower.vo.User">
	update user 
	<set>
		<if test="userName != null">
			userName = #{userName},
		</if>
		<if test="passWord != null">
			passWord = #{passWord},
		</if>
	</set>
	where 1 = 1
	<if test="id != null">
		and id = #{id}
	</if>
</update>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 删除redis中已有的缓存数据,重新请求接口:
    修改请求:
    在这里插入图片描述
    获取数据请求:
    在这里插入图片描述
    控制台日志:
    在这里插入图片描述
    redis数据库信息:
    在这里插入图片描述
  • 第一次请求结束后,更改数据重新更新再获取
    修改请求:
    在这里插入图片描述
    redis数据库此时的信息:
    在这里插入图片描述
    再次获取:
    在这里插入图片描述
    控制台日志:
    在这里插入图片描述

使用@Cacheable注解信息,在初次请求更新操作时,修改数据库信息;
如果redis中也有对应信息,则一并修改。
再次请求查询接口,发现Redis中存在最新的记录信息,此时直接从Redis中读取缓存。

@CacheEvict 注解

该注解用于删除Redis中对应的缓存信息。
写一个demo,例如:

控制类:

@GetMapping("/deluser/{id}")
@ApiOperation(value = "删除用户信息",notes = "delUser")
@ApiImplicitParam(name = "id", value = "用户id", paramType = "path", required = true, dataType = "String")
public User delUser(@PathVariable(value = "id") Integer id) {
	log.info("----queryUser---id---{}",String.valueOf(id));
	userServiceImpl.delUserById1(id);
	return null;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

业务实现类:

@Override
@CacheEvict(key = "#id")
public void delUserById1(Integer id) {
	userMapper.delUserById1(id);
}
  • 1
  • 2
  • 3
  • 4
  • 5

dao接口:

@Delete("delete from user where id = #{id}")
void delUserById1(Integer id);
  • 1
  • 2

请求之前,Redis数据库和mysql数据库数据信息:
在这里插入图片描述
在这里插入图片描述

请求测试:
在这里插入图片描述
此时的redis和mysql数据库信息:
在这里插入图片描述
在这里插入图片描述

@Caching注解

此项注解用于包含多种类型的缓存操作。

比如,有时候的业务需求,需要同时删除某些数据,更新某些数据。

更细节的注解信息汇总

命令

命令说明
Cache缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等
CacheManager缓存管理器,管理各种缓存(cache)组件
@Cacheable主要针对方法配置,能够根据方法的请求参数对其进行缓存
@CacheEvict清空缓存
@CachePut保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新
@EnableCaching开启基于注解的缓存
keyGenerator缓存数据时key生成策略
serialize缓存数据时value序列化策略
@CacheConfig统一配置本类的缓存注解的属性

@Cacheable/@CachePut/@CacheEvict 主要的参数

名称说明
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个
例如:
@Cacheable(value=”mycache”) 或者
@Cacheable(value={”cache1”,”cache2”}
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,
如果不指定,则缺省按照方法的所有参数进行组合
例如:@Cacheable(value=”testcache”,key=”#id”)
condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,
只有为 true 才进行缓存/清除缓存
例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless否定缓存。当条件结果为TRUE时,就不会缓存。
@Cacheable(value=”testcache”,unless=”#userName.length()>2”)
allEntries
(@CacheEvict )
是否清空所有缓存内容,缺省为 false,如果指定为 true,
则方法调用后将立即清空所有缓存
例如:
@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation
(@CacheEvict)
是否在方法执行前就清空,缺省为 false,如果指定为 true,
则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法
执行抛出异常,则不会清空缓存
例如:@CachEvict(value=”testcache”,beforeInvocation=true)

SpEL上下文数据

名称位置描述示例
methodNameroot对象当前被调用的方法名#root.methodname
methodroot对象当前被调用的方法#root.method.name
targetroot对象当前被调用的目标对象实例#root.target
targetClassroot对象当前被调用的目标对象的类#root.targetClass
argsroot对象当前被调用的方法的参数列表#root.args[0]
cachesroot对象当前方法调用使用的缓存列表#root.caches[0].name
Argument Name执行上下文当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数#artsian.id
result执行上下文方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false)#result

注意:

1.当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如

@Cacheable(key = “targetClass + methodName +#p0”)

2.使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:

@Cacheable(value=“users”, key="#id")

@Cacheable(value=“users”, key="#p0")

运算符

类型运算符
关系<,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne
算术+,- ,* ,/,%,^
逻辑&&,||,!,and,or,not,between,instanceof
条件?: (ternary),?: (elvis)
正则表达式matches
其他类型?.,?[…],![…],^[…],$[…]

参考资料

史上最全的Spring Boot Cache使用与整合

springboot整合spring @Cache和Redis

Demo下载

github地址

gitee地址

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号