【Spring学习】Spring Data Redis:RedisTemplate、Repository、Cache注解

1,spring-data-redis官网

1)特点

  1. 提供了对不同Redis客户端的整合(Lettuce和Jedis)
  2. 提供了RedisTemplate统一API来操作Redis
  3. 支持Redis的发布订阅模型
  4. 支持Redis哨兵和Redis集群
  5. 支持基于Lettuce的响应式编程
  6. 支持基于JDK、JSON、字符串、Spring独享的数据序列化及反序列化
  7. 支持基于Redis的JDKCollection实现

2,RedisTemplate

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。

1)常用API

api说明
redisTemplate.opsForValue();操作字符串
redisTemplate.opsForHash();操作hash
redisTemplate.opsForList();操作list
redisTemplate.opsForSet();操作set
redisTemplate.opsForZSet();操作有序set
redisTemplate.expire(key, 60 * 10000 * 30, TimeUnit.MILLISECONDS);设置过期时间

1>API:String

redisTemplate.opsForValue().set("name","tom")
说明api备注
添加单值.set(key,value)
获取单值.get(key)
添加单值并返回这个值是否已经存在.setIfAbsent(key, value)
添加单值并返回旧值.getAndSet(key, value)
批量添加Map<String,String> maps;
.multiSet(maps)
批量获取List<String> keys;
.multiGet(keys)
数值型+1.increment(key,1)
设置过期时间set(key, value, timeout, TimeUnit.SECONDS)过期返回null
字符串追加.append(key,"Hello");

2>API:List数据

template.opsForList().range("list",0,-1)
说明api备注
单个插入Long leftPush(key, value);返回操作后的列表的长度
批量插入Long leftPushAll(K key, V… values);返回操作后的列表的长度;
values可以是String[]List<Object>
查看.range(key,0,-1)从左往右:0,1,2;
从右往左:-1,-2,-3;
可做分页
弹出最左边的元素.leftPop("list")弹出之后该值在列表中将不复存在
修改set(key, index, value)
key存在则插入Long rightPushIfPresent(K key, V value);返回操作后的列表的长度
求subList.trim(key,1,-1)
移除元素Long remove(key, long count, Object value);count> 0:删除从左到右共count个等于value的元素。
count <0:删除等于从右到左共count个等于value的元素。
count = 0:删除等于value的所有元素。
求长度.size(key)

3>API:Hash操作

一个key1对应一个Map,map中每个value中@class后面对应的值为类信息。
在这里插入图片描述

template.opsForHash().put("redisHash","name","tom");
说明api备注
单插入.put(redisKey,hashKey, value)
批量插入Map<String,Object> map
.putAll(key, map)
查单数据.get(redisKey,hashKey)
查所有数据.entries(redisHash)
查key是否存在Boolean hasKey(redisKey, Object hashKey);
批量获取Hash值List multiGet(redisKey, List<Object> kes);
获取key集合Set keys(redisKey)
批量删除Long delete(redisKey, Object… hashKeys)
数值型value + 5increment(redisKey, hashKey, 5)返回操作后的value值
hashkey不存在时设置valueBoolean putIfAbsent(redisKey,hashKey, value)存在返回true,不存在返回true

遍历:

Cursor<Map.Entry<Object, Object>> curosr = template.opsForHash().scan("redisHash", ScanOptions.ScanOptions.NONE);
        while(curosr.hasNext()){
            Map.Entry<Object, Object> entry = curosr.next();
            System.out.println(entry.getKey()+":"+entry.getValue());
        }

4>API:Set数据

template.opsForSet().add(k,v)
说明api备注
添加Long add(key, V… values);values可以是:String[]
查看所有.members(key)
查询长度.size(key)
查询元素是否存在Boolean isMember(key, Object o);
批量删除Long remove(key, Object… values);values可以是:String[]
随机移除V pop(K key);
将元素value 从 sourcekey所在集合移动到 destKey所在集合Boolean move(sourcekey, V value, destKey)移动后sourcekey集合再没有value元素,destKey集合去重。
求两个集合的交集Set intersect(K key, K otherKey);
求多个无序集合的交集Set intersect(K key, Collection otherKeys);
求多个无序集合的并集Set union(K key, Collection otherKeys);

遍历:

Cursor<Object> curosr = template.opsForSet().scan("setTest", ScanOptions.NONE);
        while(curosr.hasNext()){
            System.out.println(curosr.next());
        }

5>API:ZSet集合

有序的Set集合,排序依据是Score。

template.opsForZSet().add("zset1","zset-1",1.0)
说明api备注
添加单个元素Boolean add(k, v, double score)返回元素是否已存在
批量添加元素Long add(k, Set<TypedTuple> tuples)举例:见下文1.
批量删除Long remove(K key, Object… values);
排序按分数值asc,返回成员o的排名Long rank(key, Object o);排名从0开始
排序按分数值desc,返回成员o的排名Long reverseRank(key, Object o);排名从0开始
按区间查询,按分数值ascSet range(key, 0, -1);
增加元素的score值,并返回增加后的值Double incrementScore(K key, V value, double delta);
  1. 批量添加元素
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<Object>("zset-5",9.6);
        ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<Object>("zset-6",9.9);
        Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
        tuples.add(objectTypedTuple1);
        tuples.add(objectTypedTuple2);
        System.out.println(template.opsForZSet().add("zset1",tuples));
        System.out.println(template.opsForZSet().range("zset1",0,-1));
  1. 遍历
Cursor<ZSetOperations.TypedTuple<Object>> cursor = template.opsForZSet().scan("zzset1", ScanOptions.NONE);
        while (cursor.hasNext()){
            ZSetOperations.TypedTuple<Object> item = cursor.next();
            System.out.println(item.getValue() + ":" + item.getScore());
        }

2)使用

1>依赖

<!--        Redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
<!--        连接池依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

2>配置文件

spring:
  redis:
    host: 127.0.0.1  # Redis服务器地址
    port: 6379       # Redis服务器连接端口 
    timeout:0        # 连接超时时间(毫秒)
#   database: 0      # Redis数据库索引(默认为0)
#   password:        # Redis服务器连接密码(默认为空)
    lettuce:         # 使用的是lettuce连接池
      pool:
        max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
        max-idle: 8   # 连接池中的最大空闲连接
        min-idle: 0   # 连接池中的最小空闲连接
        max-wait: 100 # 连接池最大阻塞等待时间(使用负值表示没有限制)

1>序列化配置

RedisTemplate默认采用JDK的序列化工具,序列化为字节形式,在redis中可读性很差。
修改默认的序列化方式为jackson:

@Configuration
public class RedisConfig {
    @Bean     //RedisConnectionFactory不需要我们创建Spring会帮助我们创建
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
//        1.创建RedisTemplate对象
          RedisTemplate<String,Object> template = new RedisTemplate<>();
//        2.设置连接工厂
          template.setConnectionFactory(connectionFactory);
//        3.创建JSON序列化工具
          GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//        4.设置Key的序列化
          template.setKeySerializer(RedisSerializer.string());
          template.setHashKeySerializer(RedisSerializer.string());
//        5.设置Value的序列化   jsonRedisSerializer使我们第三步new出来的
          template.setValueSerializer(jsonRedisSerializer);
          template.setHashValueSerializer(jsonRedisSerializer);
//        6.返回
        return template;
        
    }
}

但是json序列号可能导致一些其他的问题:JSON序列化器会将类的class类型写入到JSON结果中并存入Redis,会带来额外的内存开销。
为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key哈value,当要存储Java对象时,手动完成对象的序列化和反序列化。

4>java实现

public class RedisUtil {
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 批量删除对应的value
     * 
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key
     * 
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }
    
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    public String get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        if (result == null) {
            return null;
        }
        return result.toString();
    }
    
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean hmset(String key, Map<String, String> value) {
        boolean result = false;
        try {
            redisTemplate.opsForHash().putAll(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public Map<String, String> hmget(String key) {
        Map<String, String> result = null;
        try {
            result = redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

3)StringRedisTemplate

key和value的序列化方式默认就是String方式,省去了我们自定义RedisTemplate的过程。

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
//  JSON工具
    private static final ObjectMapper mapper = new ObjectMapper();
 
    @Test
    void testStringTemplate() throws JsonProcessingException {
//      准备对象
        User user = new User("abc", 18);
//      手动序列化
        String json = mapper.writeValueAsString(user);
//      写入一条数据到Redis
        stringRedisTemplate.opsForValue().set("user:200",json);
 
//      读取数据
        String s = stringRedisTemplate.opsForValue().get("user:200");
//      反序列化
        User user1 = mapper.readValue(s,User.class);
        System.out.println(user1);
    }

3,Redis数据序列化

4,Repository操作

5,Spring Cache

Spring 3.1 引入了对 Cache 的支持,使用使用 JCache(JSR-107)注解简化开发。

1)org.springframework.cache.Cache接口

  1. 包含了缓存的各种操作集合;
  2. 提供了各种xxxCache 的实现,比如:RedisCache
    在这里插入图片描述

2)org.springframework.cache.CacheManager接口

  1. 定义了创建、配置、获取、管理和控制多个唯一命名的 Cache。这些 Cache 存在于 CacheManager 的上下文中。
  2. 提供了各种xxxCacheManager 的实现,比如RedisCacheManager。

3)相关注解

1>@EnableCaching

  1. 开启基于注解的缓存;
  2. 作用在缓存配置类上或者SpringBoot 的主启动类上;

2>@Cacheable

缓存注解。

使用注意:

  1. 基于AOP去实现的,所以必须通过IOC对象去调用。
  2. 要缓存的 Java 对象必须实现 Serializable 接口。
@Cacheable(
            cacheNames = "usersBySpEL",
            //key通过变量拼接
            key="#root.methodName + '[' + #id + ']'",
            //id大于1才缓存。可缺省
            condition = "#id > 1",
            //当id大于10时,条件为true,方法返回值不会被缓存。可缺省
            unless = "#id > 10")
    public User getUserBySpEL(Integer id) {
    }
    
@Cacheable(value = {"menuById"}, key = "'id-' + #menu.id")
    public Menu findById(Menu menu) {
        return menu;
    }
常用属性说明备注代码示例
cacheNames/value缓存名称,用来划分不同的缓存区,避免相同key值互相影响。可以是单值、数组;
在redis中相当于key的一级目录,支持:拼接多层目录
cacheNames = "users"
cacheNames = {"users","account"}
key缓存数据时使用的 key,默认是方法参数。
可以使用 spEL 表达式来编写
keyGeneratorkey 的生成器,统一管理key。key 和 keyGenerator 二选一使用,同时使用会导致异常。keyGenerator = "myKeyGenerator"
cacheManager指定缓存管理器,从哪个缓存管理器里面获取缓存
condition可以用来指定符合条件的情况下才缓存
unless否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存通过 #result 获取方法结果进行判断。
sync是否使用异步模式。默认是方法执行完,以同步的方式将方法返回的结果存在缓存中

spEL常用元数据:

说明示例备注
#root.methodName当前被调用的方法名
#root.method.name当前被调用的方法
#root.target当前被调用的目标对象
#root.targetClass当前被调用的目标对象类
#root.args[0]当前被调用的方法的参数列表
#root.cacheds[0].name当前方法调用使用的缓存区列表
#参数名 或 #p0 或 #a0方法的参数名; 0代表参数的索引
#result方法执行后的返回值如果没有执行则没有内容

3>@CachePut

主要针对配置,能够根据方法的请求参数对其结果进行缓存。

  1. 区别于 @Cacheable,它每次都会触发真实方法的调用,可以保证缓存的一致性。
  2. 属性与 @Cacheable 类同。

4>@CacheEvict

根据一定的条件对缓存进行清空。

  1. 标记在类上时表示其中所有方法的执行都会触发缓存的清除操作;
常用属性说明备注代码示例
value
key
condition
allEntries为true时,清除value属性值中的所有缓存;默认为false,可以指定清除value属性值下具体某个key的缓存
beforeInvocation1. 默认是false,即在方法执行成功后触发删除缓存的操作;
2.如果方法抛出异常未能成功返回,不会触发删除缓存的操作
3.当改为true时,方法执行之前会清除指定的缓存,这样不论方法执行成功还是失败都会清除缓存

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/383388.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Android】使用Android Studio运行Hello World项目

文章目录 1. JDK的安装与配置2. Android Studio的安装3. 运行Hello World项目3.1 新建项目3.2 修改项目配置3.2.1 修改UI界面3.2.2 配置 Android SDK 3.3 添加并运行虚拟设备3.4 运行项目 1. JDK的安装与配置 想要使用Android Studio&#xff0c;必须先配置Java环境&#xff0…

ArcGIS学习(七)图片数据矢量化

ArcGIS学习(七)图片数据矢量化 通过上面几个任务的学习,大家应该已经掌握了ArcGIS的基础操作,并且学习了坐标系和地理数据库这两个非常重要且稍微难一些的专题。从这一任务开始,让我们进入到实战案例板块。 首先进入第一个案例一一图片数据矢量化。 我们在平时的工作学…

自然语言处理(NLP)—— 基本概念

自然语言处理&#xff08;Natural Language Processing&#xff0c;简称NLP&#xff09;是人工智能和语言学领域的一个分支&#xff0c;它涉及到计算机和人类&#xff08;自然&#xff09;语言之间的相互作用。它的主要目标是让计算机能够理解、解释和生成人类语言的数据。NLP结…

Solidworks:平面草图练习

继续练习平面草图&#xff0c;感觉基本入门了。

如何在 Windows 上恢复已删除的 Excel 文件

许多公司和个人在 Excel 电子表格中保存有价值的信息。当会议需要某个重要的 Excel 文件时&#xff0c;突然意识到您已删除或丢失该文件可能会造成严重问题。不用担心。我们将向您展示在 Windows 计算机上恢复已删除的 Excel 文件的多种方法。 如何在 Windows 上恢复已删除的 E…

腾讯云4核8G服务器可以用来干嘛?怎么收费?

腾讯云4核8G服务器适合做什么&#xff1f;搭建网站博客、企业官网、小程序、小游戏后端服务器、电商应用、云盘和图床等均可以&#xff0c;腾讯云4核8G服务器可以选择轻量应用服务器4核8G12M或云服务器CVM&#xff0c;轻量服务器和标准型CVM服务器性能是差不多的&#xff0c;轻…

bert-vits2本地部署报错疑难问题汇总

环境&#xff1a; bert-vits2.3 win 和wsl 问题描述&#xff1a; bert-vits2本地部署报错疑难问题汇总 解决方案&#xff1a; 问题1: Conda安装requirements里面依赖出现ERROR: No matching distribution found for opencc1.1.6 解决方法 需要在 Python 3.11 上使用 Op…

Acwing---839. 模拟堆

模拟堆 1.题目2.基本思想3.代码实现 1.题目 维护一个集合&#xff0c;初始时集合为空&#xff0c;支持如下几种操作&#xff1a; I x&#xff0c;插入一个数 x&#xff1b;PM&#xff0c;输出当前集合中的最小值&#xff1b;DM&#xff0c;删除当前集合中的最小值&#xff08…

sheng的学习笔记-docker部署springboot

部署文章目录&#xff1a;目录 docker部署&#xff0c;原理&#xff0c;命令&#xff0c;可以参考&#xff1a;docker原理图&#xff0c;部署&#xff0c;命令 目录 将springboot部署到docker中 遇到过的问题&#xff1a; pom配置 操作步骤 生成jar 构建镜像 查看镜像d…

UUID算法:独一无二的标识符解决方案

引言 在分布式系统和大数据环境下&#xff0c;唯一标识符的生成和管理是一项关键任务。UUID&#xff08;Universally Unique Identifier&#xff09;算法应运而生&#xff0c;成为了解决重复数据和标识符冲突的有效工具。本文将探讨UUID算法的优势和劣势&#xff0c;分析其在分…

上个月刚跟男朋友一起买了个三百万的房子,准备明年结婚,这个月他突然被裁了...

职场变动&#xff0c;尤其是裁员&#xff0c;已经成为我们无法忽视的现实。不管你是互联网大佬&#xff0c;还是刚入行的新人&#xff0c;这个问题都可能突如其来&#xff0c;影响到你的生活和计划。 想象一下&#xff0c;你和你的另一半刚刚为了将来的幸福生活&#xff0c;拼尽…

第三节 zookeeper基础应用与实战2

目录 1. Watch事件监听 1.1 一次性监听方式&#xff1a;Watcher 1.2 Curator事件监听机制 2. 事务&异步操作演示 2.1 事务演示 2.2 异步操作 3. Zookeeper权限控制 3.1 zk权限控制介绍 3.2 Scheme 权限模式 3.3 ID 授权对象 3.4 Permission权限类型 3.5 在控制台…

电商小程序04实现登录逻辑

目录 1 创建自定义方法2 获取用户名和密码3 验证用户是否同意协议4 验证用户名和密码总结 上一篇我们实现了登录功能的前端界面&#xff0c;这一篇实现一下登录的具体逻辑。 1 创建自定义方法 一般如果页面点击按钮需要有事件响应的&#xff0c;我们用自定义方法来实现。打开我…

CrossOver虚拟机软件功能相似的软件

与 CrossOver 功能相似的软件有&#xff1a; Wine&#xff1a;Wine 是一款在 Unix 和 Unix-like 系统&#xff08;如 Linux、macOS&#xff09;上运行 Windows 应用程序的兼容层。与 CrossOver 类似&#xff0c;Wine 通过模拟 Windows 的 API 来实现应用程序的兼容性。它支持大…

零售行业供应商数据分发,怎样提高安全性和效率?

零售行业是我国经济发展的重要组成&#xff0c;零售行业包罗万象&#xff0c;如包括汽车零售、日化零售、快消品零售等&#xff0c;不同细分行业的运营模式各不相同&#xff0c;但大体来说&#xff0c;零售行业都具备最基础的供应商和零售商&#xff0c;供应商将商品或服务卖给…

【蓝桥杯Python】试题 算法训练 数组移动

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 初始数组A[N]中为1,2,..,N&#xff0c;N个数字&#xff0c;现要进行M次操作&#xff0c;每次操作给定一个数字i&#xff0c;记…

Centos7安装nginx yum报错

Centos7安装nginx yum报错&#xff0c;yum源报错解决办法&#xff1a; 1、更新epel源后&#xff0c;出现yum报错 [roothacker117 ~]# yum install epel-release&#xff08;安装成功&#xff09; [roothacker117 ~]# yum install nginx&#xff08;安装失败&#xff0c;提示如…

WSL下如何使用Ubuntu本地部署Vits2.3-Extra-v2:中文特化修复版(新手从0开始部署教程)

环境&#xff1a; 硬&#xff1a; 台式电脑 1.cpu:I5 11代以上 2.内存16G以上 3.硬盘固态500G以上 4.显卡N卡8G显存以上 20系2070以上 本案例英伟达4070 12G 5.网络可连github 软&#xff1a; Win10 专业版 19045以上 WSL2 -Ubuntu22.04 1.bert-Vits2.3 Extra-v2:…

【Wio Terminal教程】使用LCD屏幕(4)

使用LCD屏幕&#xff08;4&#xff09; 一、TFT LCD的API例子1、实用图形2、数据显示3、字体4、作为背景显示 二、如何在Wio Terminal上使用LVGL图形库1、安装Seeed_Arduino_LvGL2、示例1. Bench Mark2. Stress Test3.资源 一、TFT LCD的API例子 本节为TFT LCD库的例子提供了一…

Android 10.0 锁屏壁纸 LockscreenWallpaper

前言 一、设置壁纸 通过系统设置进行锁屏壁纸和桌面壁纸的设置。 Setting 部分的代码&#xff1a; packages/apps/WallpaperPicker2/src/com/android/wallpaper/module/DefaultWallpaperPersister.java private int setStreamToWallpaperManagerCompat(InputStream inputStre…