SpringBoot2.x版本整合Redis进行数据缓存

Easter79
• 阅读 385

项目放在github:

在缓存开发中,有两个重要的接口:

在这里面:

    @Cacheable:    如果用这个注解标注在方法上,那么方法的结果就会被缓存存起来,这个多用于在查询的时候进行使用

     比如: public user getuser(Integer id) 这个方法用这个注解标注的话,通过id查到的内容就会杯存在缓存中进行保存,如果下次在进行查同样id的信息的话,直接从缓存中进行调取就行了,大大减少了大系统的数据库的负担

    @CacheEvict:  如果用这个注解标注在方法的话,就会把对应的缓存进行删除,这个注解多用于再删除的模块上,再删除数据的时候,将对应的缓存也进行删除

    @CachePut:    更新缓存,在更新的时候,多用到

    比如:public User updadeuer(User user)这样的方法,就是将之前的信息进行修改,并且进行提交,这个缓存机制也是,在更新之后,将缓存的数据信息也进行更新

    @EnableCacheing:要想使用注解,就得启用注解的模式,并且还有key,和value的的对应关系问题

在我们进行缓存项目创建的时候,我们要选中cache的缓存模块,将自动导入我们想要的缓存的依赖

并且要导入redis的依赖,才能使用,否则会报错:

<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.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency>

在@Cache中有几个重要的属性:

cacheName/value:指定缓存组件的名称,这个就是将缓存进行存取的时候的名称,将方法的返回结果放在缓存中,可以制定多个缓存(是数组的形式)。

key:如果不指定的话,系统默认的就是我们的方法传递的参数:

例如;

@Cacheable(cacheNames = {"emp"})
public Employee getEmp(Integer id){
  System.out.println("查询"+id+"号员工信息");
  Employee emp = employeeMapper.getEmpById(id);
  return emp;
}

这种不进行指定的话,我们的key默认就是“2”

我们也可以自己进行指定:

1、利用key进行自定义生成

    key="root.methodName"+'['+#id+']'"

    这种形式生成的key就是getEmp【2】,   root.methodName就是获取方法的名称

2、可以自定义keygenerator,按照自己生成器进行生成我们想要的key

    

    @Bean
    public KeyGenerator keyGenerator(){
//        return (o, method, params) ->{
//            StringBuilder sb = new StringBuilder();
////            sb.append(o.getClass().getName()); // 类目
////            sb.append(method.getName()); // 方法名
//            for(Object param: params){
//                sb.append(param.toString()); // 参数名
//            }
//            return sb.toString();
//        };
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                return Arrays.asList(objects).toString();
            }
        };
    }

并且在service上用@Cacheable(cacheNames = {"emp"},keyGenerator = "myKeyGenerator")进行keygenerator的自定义器的使用

condition:做判断,例如一号员工做缓存,二号员工不做缓存:

    @Cacheable(cacheNames = {"emp"},keyGenerator = "myKeyGenerator",condition = "#id>1" and....)

这种就是判断在id>1的情况下,才会进行缓存生效,否则不生效

unless:是在条件成立的时候,不进行缓存,unless="#a0==2"",这种情况就是在id为2的情况下,不进行缓存,a0就是第一个参数的意思,也就是这里的id

@CachePut(更新数据信息,更新缓存的注解)

这种方法多用在更新信息的情况下进行使用

例如:

@CachePut(cacheNames = {"emp"},key = "#employee.id")
public Employee updateEmp(Employee employee){
  System.out.println("修改"+employee.getId()+"号员工信息");
  employeeMapper.updateEmp(employee);
  return employee;
}

/*

* @CachePut:既调用方法,又更新缓存信息

* 运行时机:

* 1、先调用目标方法

* 2、将目标方法的结果缓存起来

* (这里需要注意的是,在更新缓存数据信息的时候,因为我们的key是不同的,前面默认的是id=xx,这里用的是employee,

* 所以需要将key进行统一,这样才能更新缓存的数据信息)

*

* */

这里就是要注意将我们更新的缓存的key和前面缓存的信息的key要保持一致,否则不能进行缓存的修改

@CacheEvict:在进行缓存的删除时候,也要指定对应的value和key,这样才能删除对应的缓存信息

@CacheEvict(value = {"emp"},key = "#id",allEntries = false,beforeInvocation = false)
public void deleteEmp(Integer id){
    System.out.println("删除"+id+"号员工信息");
    employeeMapper.deleteEmp(id);
}

其中的allEntries默认为false,如果改成true,那么emp中所有的缓存信息都会被清空

beforeInvocation = false,这个默认也是false,是指定是不是在方法运行之后进行缓存的清除

也可以在最上面加上CacheConfig,这个就是在上面抽取缓存的共同配置,如cacheName等等

然后就是在application.properties或者是application.yml文件中配置我们的redis的相关配置:

#配置redis

redis:
host: 192.168.43.197
port: 6379
database: 0

这些是最基本的一些配置,其余的配置可在官网进行查询得知:

redis是安装在虚拟机docker里面的,在本地安装上redisdesktop可以操作虚拟机里面的redis。

SpringBoot从1.x升级到2.x的redis进行了改革换代,前面的东西和后面的东西差距太大,这里操作2。x版本的SpringBoot需要进行相关的序列化的配置,自己编写config文件进行相关的序列化的操作,config文件代码:

package com.example.cache.config;
import  org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.*;

import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Arrays;

/*
 *   Redis中常见的五种数据类型
 *       String(字符串)、List(列表)、Set(集合)、Hash(散列)、ZSet(有序集合)
 *
 * */
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport{
    private static final Logger logger = LoggerFactory.getLogger(RedisCacheConfig.class);
    // 自定义key生成器
    @Bean
    public KeyGenerator keyGenerator(){
//        return (o, method, params) ->{
//            StringBuilder sb = new StringBuilder();
////            sb.append(o.getClass().getName()); // 类目
////            sb.append(method.getName()); // 方法名
//            for(Object param: params){
//                sb.append(param.toString()); // 参数名
//            }
//            return sb.toString();
//        };
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                return Arrays.asList(objects).toString();
            }
        };
    }

    // 配置缓存管理器
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600000)) // 60s缓存失效
                // 设置key的序列化方式
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                // 设置value的序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                // 不缓存null值
                .disableCachingNullValues();

        RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();

        logger.info("自定义RedisCacheManager加载完成");
        return redisCacheManager;
    }
  /*  @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setKeySerializer(keySerializer());
        redisTemplate.setHashKeySerializer(keySerializer());
        redisTemplate.setValueSerializer(valueSerializer());
        redisTemplate.setHashValueSerializer(valueSerializer());
        logger.info("序列化完成!");
        return redisTemplate;
    }*/

    // key键序列化方式
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    // value值序列化方式
    private GenericJackson2JsonRedisSerializer valueSerializer(){
        return new GenericJackson2JsonRedisSerializer();
    }
}

然后再我们的service中进行相关的增删改查的时候,就可以加上缓存注解,进行操作redis的缓存数据库

package com.example.cache.service;

import com.example.cache.bean.Employee;
import com.example.cache.mapper.EmployeeMapper;
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.stereotype.Service;

@Service
public class EmployeeService {
    @Autowired
    EmployeeMapper employeeMapper;
    //查询员工信息
    /*
    *@Cacheable
    * 开启缓存,将方法的运行结果缓存起来,下次在相同的查询,就在缓存中查询
    * CacheManager管理多个Cache组件,每一个缓存组件都有自己唯一的名称
    * 几个属性:
    *   cacheName/value:指定缓存组件的名称
    *   key:缓存数据用的值,可以用它来指定,默认是使用方法参数的值,1-方法的返回值
    *   keyGenerator:主键生成器,也可以自己指定主键生成器
    *       key/keyGenerator二选一使用
    *   cacheManager:缓存管理器
    *   cacheResolver:缓存解析器
    *       cacheManager/cacheResolver二选一
    *   condition:指定符合条件的情况下,才进行缓存
    *       可以进行指定条件
    *   unless:否定缓存,当unless指定的条件为true时候,方法的缓存不会被缓存
    *   sync:异步模式:指定是否使用异步模式
    * */
    @Cacheable(cacheNames = {"emp"})
//    ,keyGenerator = "myKeyGenerator",condition = "#id>1" ,unless="#a0==2"
    public Employee getEmp(String lastname){
        System.out.println("查询"+lastname+"号员工信息");
        Employee emp = employeeMapper.getEmpByName(lastname);
        return emp;
    }

    //删除员工信息
    /*
    *@CacheEvict:清除注解,将缓存里面的信息进行清除
    *,allEntries = false,
    * beforeInvocation = false
     */
    @CacheEvict(value = {"emp"},key = "'['+#lastname+']'")
    public void deleteEmp(String lastname){
        System.out.println("删除"+lastname+"员工信息");
        employeeMapper.deleteEmp(lastname);
    }
    //增加员工信息,这里不做缓存
//    @CacheEvict(value = {"emp"},key = "'['+#employee.getLastName()+']'")
    public void insertEmp(Employee employee){
        System.out.println("增加新的员工信息");
        employeeMapper.insertEmp(employee);
    }
    //修改员工信息
    /*
    * @CachePut:既调用方法,又更新缓存信息
    *       运行时机:
    *           1、先调用目标方法
    *           2、将目标方法的结果缓存起来
    *         (这里需要注意的是,在更新缓存数据信息的时候,因为我们的key是不同的,前面默认的是id=xx,这里用的是employee,
    *           所以需要将key进行统一,这样才能更新缓存的数据信息)
    *
    * */
    @CachePut(cacheNames = {"emp"},key = "'['+#employee.getLastName()+']'")
    public Employee updateEmp(Employee employee){
        System.out.println("修改"+employee.getLastName()+"员工信息");
        employeeMapper.updateEmp(employee);
        return employee;
    }
}

这样,redis的缓存数据库就配置好了

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
SpringBoot2.x版本整合Redis进行数据缓存
项目放在github:在缓存开发中,有两个重要的接口:在这里面:  @Cacheable:  如果用这个注解标注在方法上,那么方法的结果就会被缓存存起来,这个多用于在查询的时候进行使用    比如: publicusergetuser(Integerid) 这个方法用这个注解标注的话,通过id查到的内容就会杯存在缓存中进行保存
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k