P0级事故,项目组慌的一批! 下

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: P0级事故,项目组慌的一批! 下

接下来我们验证下场景 4,先执行 Redis 事务操作,然后在不添加 @Transactional 注解的方法中执行 Redis 递增操作。

用 Postman 调用这个接口后,正常返回自增后的结果,并不是返回 null。说明在非 @Transactional 中执行 Redis 操作并没有受到 Redis 事务的影响。

四个场景的结论如下所示,只有第三个场景下,Redis 的递增操作才会返回 null。

问题原因找到了,说明 RedisTemplete 开启了 Redis 事务支持后,在 @Transactional 中执行的 Redis 命令也会被认为是在 Redis 事务中执行的,要执行的递增命令会被放到队列中,不会立即返回执行后的结果,返回的是一个 null,需要等待事务提交时,队列中的命令才会顺序执行,最后 Redis 数据库的键值才会递增。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

三、源码解析

那我们就看下为什么开启了 Redis 事务支持,效果就不一样了。

找到 Redis 执行命令的核心方法, execute 方法。

然后一步一步点进去看,关键代码就是 211 行到 216 行,有一个逻辑判断,当开启了 Redis 事务支持后,就会去绑定一个连接(bindConnection),否则就去获取新的 Redis 连接(getConnection)。这里我们是开启了的,所以再到 bindConnection方法中查看如何绑定连接的。

image.png

接着往下看,关键代码如下所示,当开启了 Redis 事务支持,且添加了 @Transactional 注解时,就会执行 Redis 的 mutil 命令。

关键代码:conn.multi();

Redis Multi 命令 用于标记一个事务块的开始,事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。

真相大白,开启 Redis 事务支持 + @Transactional 注解后,最后其实是标记了一个 Redis 事务块,后续的操作命令是在这个事务块中执行的。

比如下面的的递增命令并不会返回递增后的结果,而是返回 null。

stringRedisTemplate.opsForValue().increment("count", 1);

而我们的生产环境重启服务后,开启的 Redis 事务支持又被重置为默认值了,所以后续的 Redis 递增操作都能正常执行。

四、修复方案

目前想到了两种解决方案:

  • 方案一:每次 Redis 的事务操作完成后,关闭 Redis 事务支持,然后再执行 @Transactional 中的 Redis 命令。(有弊端
  • 方案二:创建两个 StringRedisTemplate,一个专门用来执行 Redis 事务,一个用来执行普通的 Redis 命令。

4.1 方案一

方案一的写法如下,先开启事务支持,事务执行之后,再关闭事务支持。

image.png

但是这种写法有个弊端 ,如果在执行 Redis 事务期间,在 @Transactional 注解的方法里面执行 Redis 命令,则还是会造成返回结果为 null。

4.2 方案二

弄两个 RedisTemplate Bean,一个是用来执行 Redis 事务的,一个是用来执行普通 Redis 命令的(不支持事务)。不同的地方引入不同的 Bean 就可以了。

先创建一个 RedisConfig 文件,自动装配两个 Bean。一个 Bean 名为 stringRedisTemplate 代表不支持事务的,执行命令后立即返回实际的执行结果。另外一个 Bean 名为 stringRedisTemplateTransaction,代表开启 Redis 事务支持的。

代码如下所示:

接下来在测试的 Service 类中注入两个不同的 StringRedisTemplate 实例,代码如下所示:

Redis 事务的操作改写成这样,且不需要手动开启 Redis 事务支持了。用到的 StringRedisTemplate 是支持事务的那个实例。

在 Spring 的 @Tranactional 中执行的 Redis 命令如下所示,用到的 StringRedisTemplate 是不支持事务的那个实例。

image.png

然后还是按照上面场景 3 的测试步骤,先执行 testRedisMutil 方法,再执行 testTransactionAnnotations 方法。

验证结果 :Redis 递增操作正常返回 count 的值,修复完成。

参考资料:https://blog.csdn.net/qq_34021712/article/details/79606551



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
数据采集 存储 监控
CDGA|做好数据治理的几个策略,不看后悔
做好数据治理是企业实现数字化转型和智能化升级的关键。通过明确目标、建立组织、制定标准、实施质量管理、促进共享与协作以及持续优化与迭代等策略,企业可以构建完善的数据治理体系,提升数据价值,为业务决策提供有力支持。在未来的发展中,数据治理将成为企业核心竞争力的重要组成部分。
|
7月前
|
测试技术 程序员 项目管理
甲方怒喷半小时:一次项目上线失败的深刻教训
小米分享了一次项目上线失败的经历,起因是运营提出一个看似简单的白名单功能。问题包括:没有需求原型导致理解偏差,新成员对项目不熟悉,测试流程不全面,以及人员变动大。解决方案涉及需求确认会、原型图设计、交接制度、团队培训和全流程测试等。这次失败提供了关于需求分析、项目管理及团队协作的教训。
62 2
|
前端开发 Shell 程序员
🙊整活向:定期给老板推送同事的代码量
总有领导想把公司往倒闭里整。但是每天推送每个人的代码量倒是挺有趣的,git log本身就自带这个功能,不来看看吗?
179 0
🙊整活向:定期给老板推送同事的代码量
|
NoSQL JavaScript 前端开发
P0级事故,项目组慌的一批! 上
P0级事故,项目组慌的一批! 上
|
程序员 项目管理
新晋主管十分钟掌握如何做好管理工作
新晋主管十分钟掌握如何做好管理工作
355 0
新晋主管十分钟掌握如何做好管理工作
|
数据采集 运维 数据管理
信息部门牵头实施的主数据项目效果不好,如何挽救?
最近和大型企业的信息部门就主数据项目的实施进行了很多次交流,大家普遍存在一个非常困扰问题:信息部门牵头实施的主数据效果不好,怎么去挽救?怎么去改善?
信息部门牵头实施的主数据项目效果不好,如何挽救?
|
人工智能 数据可视化 安全
开工推迟,多国封锁边境,疫情期如何做好远程开发?
面对新冠病毒肺炎,我们人人都在家中难以出门,还是在家远程码代码吧。
165 0
开工推迟,多国封锁边境,疫情期如何做好远程开发?
汇报时,如何让老板快速抓住重点? | 黄金三步法
阿里妹导读:对事物的归类分组是我们人类的天性,我们的大脑会自动将发现的所有事物以某种持续组织起来。但如何组织才能帮助我们解决工作和生活中出现的各种复杂问题?今天,我们请阿里高级技术专家张建飞分享他的黄金三步法。
5737 0
2020年中央引导地方科技发展资金预算提前下达,约14亿元
11月20日,财政部网站发布《提前下达2020年中央引导地方科技发展资金预算的通知》。《通知》数据显示,提前下达预算指标合计138950万元,将统筹用于支持基础研究、科技创新基地建设、科技成果转移转化和区域创新体系建设等方面。
下一篇
DataWorks