Springboot redisson 自定义注解实现双写一致性

在 Spring Boot 项目中使用 Redisson 实现双写一致性(即数据库和缓存的一致性),可以通过自定义注解和 AOP(面向切面编程)来简化代码并提高可维护性。以下是一个具体的案例,展示了如何使用自定义注解和 AOP 来实现这一目标。

实现步骤

1.添加依赖

首先,确保你的项目中包含了 Redisson 和 Spring Boot 的依赖。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><!-- Redisson -->
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.16.3</version>
</dependency>

2.配置 Redisson

在 application.yml 中配置 Redisson 客户端连接到 Redis 服务器。

spring:redis:host: localhostport: 6379redisson:singleServerConfig:address: redis://${spring.redis.host}:${spring.redis.port}

3.添加配置类:

@Configuration
public class RedissonConfig {@Value("${redisson.singleServerConfig.address}")private String redisAddress;@Bean(destroyMethod = "shutdown")public RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress(redisAddress);return Redisson.create(config);}
}

 4.自定义注解

创建一个自定义注解,另一个注解还用上篇的

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CustomerCacheEvict {/*** 缓存名称* @return*/String key() default "";
}

5.AOP 切面

创建一个切面类 CustomCacheAspect,使用 Redisson 的读写锁来实现缓存和数据库的一致性。

@Aspect
@Component
public class CustomCacheAspect {@Resourceprivate RedisTemplate<String, Object> redisTemplate;@Resourceprivate RedissonClient redissonClient;@Around("@annotation(customCacheable)")public Object cache(ProceedingJoinPoint joinPoint, CustomCacheable customCacheable) throws Throwable {Object result;String key = customCacheable.key();long expireTime = customCacheable.expireTime();//获取参数值key = getKey(joinPoint, key);// 加锁RLock rLock = redissonClient.getReadWriteLock(key+":lock").readLock();rLock.lock();try {// 尝试从缓存中获取数据Object cachedValue = redisTemplate.opsForValue().get(key);if (cachedValue != null) {return cachedValue;}// 读锁升级为写锁,执行数据库查询操作    rLock.unlock();RLock wLock = redissonClient.getReadWriteLock(key + ":lock").writeLock();wLock.lock();try {// 再次检查缓存,避免在获取写锁期间,其他线程已填充缓存cachedValue = redisTemplate.opsForValue().get(key);if (cachedValue != null) {return cachedValue; // 直接返回缓存值}// 如果缓存中没有数据,则执行方法并将结果存入缓存result = joinPoint.proceed();// 设置缓存if(expireTime > 0){redisTemplate.opsForValue().set(key, result, expireTime, TimeUnit.SECONDS);}else{redisTemplate.opsForValue().set(key, result);}}finally{if(wLock.isHeldByCurrentThread()) {wLock.unlock();}}}finally{if(rLock.isHeldByCurrentThread()){rLock.unlock();}}return result;}@Around("@annotation(customerCacheEvict)")public Object cache(ProceedingJoinPoint joinPoint, CustomerCacheEvict customerCacheEvict) throws Throwable {Object result;String key = customerCacheEvict.key();//获取参数值key = getKey(joinPoint, key);// 加锁RLock wLock = redissonClient.getReadWriteLock(key + ":lock").writeLock();wLock.lock();try {result = joinPoint.proceed();try {Thread.sleep(100);}catch (Exception e){e.printStackTrace();}redisTemplate.delete(key);}finally{if(wLock.isHeldByCurrentThread()){wLock.forceUnlock();}}return result;}/*** 获取参数值* @return*/private String getKey(ProceedingJoinPoint joinPoint, String key) {Object[] args = joinPoint.getArgs();// 构建缓存键if (args != null && args.length > 0) {key = key + ":" + args[0];}return key;}
}

6.服务类

在接口类中使用自定义注解。(实际加到service 层更好)

    /*** 根据id查询*/@GetMapping("/{id}")@CustomCacheable(key = "user")public  UserTest getById(@PathVariable Long id) {return userTestService.getById(id);}/*** 修改*/@PutMapping("/{id}")@CustomerCacheEvict(key="user")public boolean update(@PathVariable Integer id, @RequestBody UserTest userTest) {userTest.setId(id);return userTestService.updateById(userTest);}

通过以上步骤,我们使用自定义注解和 AOP 确保了数据库和 Redis 缓存之间的一致性。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java研学-Shiro安全框架(四)

六 SpringBoot集成Shiro认证 1 分析 Shiro提供认证授权功能&#xff0c;所以SpringBoot中不需再编写自定义注解&#xff0c;权限拦截&#xff0c;登录拦截&#xff0c;登录登出。Shiro 环境中有三个封装对象Subject &#xff0c;SecurityManager和Realms&#xff0c;SpringBoo…

Java核心技术【二十一】Java的I/O流处理:文件的读写操作

Java的I/O流处理&#xff1a;文件读写操作 【创作】 不易&#xff0c;【点赞】 是情义&#xff0c;【关注】 是动力&#xff0c;【收藏】 是回忆。 示例代码地址&#xff1a;https://gitee.com/code-in-java/csdn-blog.git 在Java编程中&#xff0c;输入/输出&#xff08;I/O&a…

PyTorch实现BERT预训练模型转化指南

huggingface官方的介绍&#xff1a; https://huggingface.co/transformers/converting_tensorflow_models.html 直接用命令行 把箭头处路径改为自己放原有tf版本预训练模型的路径 回车后会有一大堆提示&#xff0c;然后发现路径下多了一个bin文件&#xff0c;加上原本的config…

顺序结构 ( 六 ) —— 顺序结构实例 【互三互三】

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e;&#x1f680;所属专栏&#xff1a;C教程&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &am…

iNavFlight飞控固件学习-1《开发环境搭建》

目录 文章目录 目录摘要1.官网2.形成Linux开发环境工具2.1 简介2.2 相关工具2.2.1 Ubuntu / Debian系统配置命令2.2.2 Fedora系统配置命令2.2.3 Fedora系统配置命令 2.3 克隆存储库2.4 构建工具2.5 使用cmake2.6 构建固件2.7 清除2.8 cmake 缓存维护2.9 编译通过ninja2.10 更新…

js 日期比较大小

在JavaScript中&#xff0c;比较日期大小通常涉及将日期转换为时间戳&#xff08;自1970年1月1日以来的毫秒数&#xff09;&#xff0c;然后比较这些时间戳。这是因为直接比较两个Date对象可能不会按预期工作&#xff0c;特别是如果你试图了解哪个日期在另一个日期之前或之后。…

红酒与未来科技:传统与创新的碰撞

在岁月的长河中&#xff0c;红酒以其深邃的色泽、丰富的口感和不同的文化魅力&#xff0c;成为人类文明中的一颗璀璨明珠。而未来科技&#xff0c;则以其迅猛的发展速度和无限的可能性&#xff0c;领着人类走向一个崭新的时代。当红酒与未来科技相遇&#xff0c;一场传统与创新…

2024.07.03校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、提前批 | 中国兵器工业集团第二〇二研究所 | 提前批/招/聘暨/暑期/开放日 提前批 | 中国兵器工业集团第二〇二研究所 | 提前批招聘暨暑期开放日 2、夏令营 | 2024年南网数字集团“未来…

ADI新型充电器解决方案可实现电池堆电压和充电效率

就目前而言&#xff0c;这可能是生活中zui常见的问题了。世纪之交&#xff0c;电池&#xff08;尤其是基于锂离子的电池&#xff09;成本的降低和性能的提高&#xff0c;推动了电池供电的储能和便携式设备的稳步增长。此外&#xff0c;超级电容器由于具有独特的性质&#xff0c…

oppo25届秋招,快手25届技术人才专项计划内推

oppo25届秋招&#xff0c;快手25届技术人才专项计划内推 ①【OPPO】25届秋招开启&#xff01; 内推简历优先筛选&#xff01; &#x1f449;岗位类别&#xff1a;AI/算法类&#xff0c;软件类&#xff0c;硬件类&#xff0c;工程技术类&#xff0c;品牌策划类&#xff0c;设计类…

骨传导耳机最热门好用款推荐,选购骨传导耳机前不能忽略的六大细节

如今的社会在耳机种类方面可以说是越来越多&#xff0c;于是很多人在挑选的时候往往选择不到适合自己的一款耳机&#xff0c;尤其是在近些年来席卷耳机市场的骨传导耳机&#xff0c;开放耳道的设计在很多时候佩戴无异于是更加的适合&#xff0c;正好小编这边对于比较热门的几款…

社交App iOS审核中的4.3问题:深入分析与解决策略

社交App审核中的4.3问题&#xff1a;深入分析与解决策略 在iOS应用开发和审核过程中&#xff0c;开发者经常会遇到苹果审核4.3问题。这一问题往往涉及应用的设计和内容重复性&#xff0c;导致应用被拒绝上架。为了帮助开发者更好地理解和解决这一问题&#xff0c;本文将对4.3问…

动漫3d模型设计需要注意什么?---模大狮模型网

设计动漫3D模型时&#xff0c;有几个方面需要注意&#xff1a; 保持角色风格一致性&#xff1a; 动漫通常有独特的风格和美学&#xff0c;设计时要确保模型与所代表的角色或作品的整体风格相符。注意保持线条和比例的一致性&#xff0c;使模型能够忠实地呈现原作的特点。 注重…

springboot餐饮管理系统-计算机毕业设计源码43667

摘 要 在信息化、数字化的时代背景下&#xff0c;餐饮行业面临着前所未有的挑战与机遇。为了提高运营效率、优化顾客体验&#xff0c;餐饮企业亟需一套高效、稳定且灵活的管理系统来支撑其日常运营。基于Spring Boot的餐饮管理系统应运而生&#xff0c;成为餐饮行业数字化转型的…

Python基础教学之一:入门篇——迈入编程世界的第一步

Python基础教学之一&#xff1a;入门篇——迈入编程世界的第一步 一、Python简介&#xff1a;历史与现状 Python&#xff0c;一种解释型、高级和通用的编程语言&#xff0c;由Guido van Rossum在1989年圣诞节期间创造&#xff0c;并于1991年首次发布。设计哲学强调代码的可读性…

论文降痕降重全攻略:从技巧到工具,助你轻松应对学术挑战

AIGC降重工具&#xff1a;快速降低论文查重率 高查重率是许多毕业生的困扰。通常&#xff0c;高查重率源于过度引用未经修改的参考资料和格式错误。传统的降重方法&#xff0c;如修改文本和增添原创内容&#xff0c;虽必要但耗时且成效不一。 鉴于此&#xff0c;应用AI工具进…

【企业级监控】源码部署Zabbix与监控主机

Zabbix企业级分布式监控 文章目录 Zabbix企业级分布式监控资源列表基础环境一、LNMP环境搭建&#xff08;在zbx主机上&#xff09;1.1、配置Yum仓库1.1.1、下载阿里云的仓库文件1.2.2、安装PHP7的仓库1.2.3、生成Mariadb10.11的仓库文件1.2.4、快速重建Yum缓存 1.2、安装PHP7.4…

请求取消(多种)

XMLHttpRequest XMLHttpRequest 可以使用 abort() 方法来实现请求取消。 const xhr new XMLHttpRequest();xhr.open(GET, http://localhost:3000/api/txt);xhr.timeout 2;xhr.ontimeout function () {xhr.abort();console.error(请求超时&#xff0c;已中断);};xhr.onload …

shell脚本之for循环

一、循环中的常见语句 1.1 echo 打印 -n &#xff1a;表示不换行输出-e &#xff1a;输出转义字符 \b &#xff1a;相当于退格键(backspace)\n &#xff1a;换行&#xff0c;相当于回车\f &#xff1a;换行&#xff0c;换行后的新行的开头连着上一行的行尾\t &#xff1a;插入…

编程用什么轴体比较好用:全面解析四种轴体的优劣与应用

编程用什么轴体比较好用&#xff1a;全面解析四种轴体的优劣与应用 在编程的世界里&#xff0c;选择一款合适的机械键盘轴体&#xff0c;不仅能提升工作效率&#xff0c;更能带来舒适的打字体验。然而&#xff0c;面对市场上琳琅满目的轴体类型&#xff0c;究竟该如何选择呢&a…