【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 {@Autowiredprivate 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的过程。

    @Autowiredprivate StringRedisTemplate stringRedisTemplate;
//  JSON工具private static final ObjectMapper mapper = new ObjectMapper();@Testvoid testStringTemplate() throws JsonProcessingException {
//      准备对象User user = new User("abc", 18);
//      手动序列化String json = mapper.writeValueAsString(user);
//      写入一条数据到RedisstringRedisTemplate.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时,方法执行之前会清除指定的缓存,这样不论方法执行成功还是失败都会清除缓存

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

HiveSQL——用户行为路径分析

注&#xff1a;参考文档&#xff1a; SQL之用户行为路径分析--HQL面试题46【拼多多面试题】_路径分析 sql-CSDN博客文章浏览阅读2k次&#xff0c;点赞6次&#xff0c;收藏19次。目录0 问题描述1 数据分析2 小结0 问题描述已知用户行为表 tracking_log&#xff0c; 大概字段有&…

如何从 iPhone 恢复已删除的视频:简单有效方法

无论您是在尝试释放空间时不小心删除了 iPhone 上的视频&#xff0c;还是在出厂时清空了手机&#xff0c;现在所有数据都消失了&#xff0c;都不要放弃。有一些方法可以恢复这些视频。 在本文中&#xff0c;我们将向您展示六种最有效的数据恢复方法&#xff0c;可以帮助您从 i…

【LeetCode每日一题】二维前缀和基本概念与案例

二维前缀和 根据某个块块 的 左上角坐标&#xff0c;和右下角坐标 求出 块块的累加和。 304. 二维区域和检索 - 矩阵不可变 /*** param {number[][]} matrix*/ var NumMatrix function(matrix) {let row matrix.length;let col matrix[0].length;// 初始化一个二维数组&am…

综合项目---博客

一.运行环境 192.168.32.132 Server-Web linux Web 192.168.32.133 Server-NFS-DNS linux NFS/DNS 基础配置 1.配置主机名静态ip 2.开启防火墙并配置 3.部分开启selinux并配置 4.服务器之间通过阿里云进行时间同步 5.服务器之间实现ssh免密…

antdpro框架npm install 报错,切换tyarn安装成功。

报错日志 有时间补 当前版本 解决办法 进入工作目录 安装官方推荐的tyarn工具&#xff1a;npm install yarn tyarn -g 进行依赖安装&#xff1a;tyarn 启动项目 &#xff1a;tyarn start 注意&#xff1a; 技术迭代较快&#xff0c;建议查询官网后实践&#xff0c;以上作为…

Java LinkedList 实现栈和队列

Java LinkedList 实现栈和队列 package com.zhong.collection;import java.util.LinkedList;public class LinkedListDemo {public static void main(String[] args) {// LinkedList 创建一个队列LinkedList<String> queue new LinkedList<>();// 进队System.out…

《UE5_C++多人TPS完整教程》学习笔记4 ——《P5 局域网连接(LAN Connection)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P5 局域网连接&#xff08;LAN Connection&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译者&…

nodejs爬虫框架

nodejs爬虫框架 在Node.js中&#xff0c;有一些常用的爬虫框架可以帮助你实现网页抓取和数据提取的任务。以下是几个流行的Node.js爬虫框架&#xff1a; 1. **Puppeteer**: Puppeteer 是由 Google 开发的一个用于控制 headless Chrome 或 Chromium 浏览器的 Node.js 库。它提供…

AlmaLinux右键菜单(基于GNOME桌面)

文章目录 前言前提说明在文件上右键在文件夹上右键 前言 在使用VSCode的过程中&#xff0c;AlmaLinux没能像Windows一样在右键菜单上显示打开方式&#xff0c;所以找了一下解决方案&#xff0c;罗列出来 前提说明 虽然说无论是media还是StackOverflow都推荐使用这条命令&…

CSP-202104-1-灰度直方图

CSP-202104-1-灰度直方图 解题思路 比较简单&#xff0c;直接上代码 #include <iostream> using namespace std; int main() {int n, m, L, aws[300] {};cin >> n >> m >> L;for (int i 0; i < n * m; i){int pixel;cin >> pixel;aws[pi…

第五篇:MySQL常见数据类型

MySQL中的数据类型有很多&#xff0c;主要分为三类:数值类型、字符串类型、日期时间类型 三个表格都在此网盘中&#xff0c;需要者可移步自取&#xff0c;如果觉得有帮助希望点个赞~ MySQL常见数据类型表 数值类型 &#xff08;注&#xff1a;decimal类型举例&#xff0c;如1…

搜索二维矩阵[中等]

一、题目 给你一个满足下述两条属性的m x n整数矩阵&#xff1a; 【1】每行中的整数从左到右按非严格递增顺序排列。 【2】每行的第一个整数大于前一行的最后一个整数。 给你一个整数target&#xff0c;如果target在矩阵中&#xff0c;返回true&#xff1b;否则&#xff0c;返…

关于java的多线程初识

关于java的多线程初识 我们从今天开始&#xff0c;正式学习java的多线程&#xff0c;我们在前面的文章中学习到了java的基础&#xff0c; 但是距离我们工作实战还差的很远&#xff0c;我们学习好了基础&#xff0c;以后的文章会逐步的深入&#xff0c;去讲解各种前端框架&…

导数的几何意义【高数笔记】

1. 高数中的导数几何意义&#xff0c;与中学中斜率的联系 2. 导函数与导数的区别和联系又是什么 3. 导数的几何意义的题型是什么 4. 这些题型又有哪些区别 5. 点在曲线外和点在曲线上&#xff0c;需要注意什么 6. 法线和切线有什么关系 7. 法线是什么

13 年后,我如何用 Go 编写 HTTP 服务(译)

原文&#xff1a;Mat Ryer - 2024.02.09 大约六年前&#xff0c;我写了一篇博客文章&#xff0c;概述了我是如何用 Go 编写 HTTP 服务的&#xff0c;现在我再次告诉你&#xff0c;我是如何写 HTTP 服务的。 那篇原始的文章引发了一些热烈的讨论&#xff0c;这些讨论影响了我今…

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

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

吹响AI PC号角!微软在Windows中不断增加“Copilot含量”

2024&#xff0c;会是AI PC元年吗&#xff1f;至少微软正在往这个方向努力。 本周&#xff0c;微软开始在Windows中测试Copilot的“新体验”&#xff0c;其中包括任务栏中的Copilot图标&#xff0c;当用户复制文本或图片时&#xff0c;Copilot操作菜单就会自动出现。 有媒体在…

解决Typora导出HTML不显示图片

解决Typora导出HTML不显示图片 产生原因 Typora导出HTML不显示图片&#xff0c;可能时图片存放在我们的硬盘中。 我们可以将markdown中的图片转化为base64格式&#xff0c;嵌入到html中。 解决步骤 首先&#xff0c;下载 TyporaToBase64.jar 密码:45jq 其次&#xff0c;将…

Linux nohup命令和

参考资料 linux后台运行nohup命令的使用及2>&1字符详解 目录 前期准备一. 基本语法二. 执行时不指定日志文件三. 执行后不想要日志文件四. nohup命令的执行与kill4.1 执行4.2 kill 前期准备 &#x1f4c4;handle_file.sh #!/bin/bashecho "文件复制开始..."…

【漏洞复现】狮子鱼CMS文件上传漏洞(wxapp.php)

Nx01 产品简介 狮子鱼CMS&#xff08;Content Management System&#xff09;是一种网站管理系统&#xff0c;它旨在帮助用户更轻松地创建和管理网站。该系统拥有用户友好的界面和丰富的功能&#xff0c;包括页面管理、博客、新闻、产品展示等。通过简单直观的管理界面&#xf…