一次 Redis 事務使用不當引發的生產事故( 三 )


stringRedisTemplate.opsForValue().increment("count", 1);而我們的生產環境重啟服務后,開啟的 Redis 事務支持又被重置為默認值了 , 所以后續的 Redis 遞增操作都能正常執行 。
四、修復方案目前想到了兩種解決方案:

  • 方案一:每次 Redis 的事務操作完成后,關閉 Redis 事務支持,然后再執行 @Transactional 中的 Redis 命令 。(有弊端)
  • 方案二:創建兩個 StringRedisTemplate , 一個專門用來執行 Redis 事務,一個用來執行普通的 Redis 命令 。
4.1 方案一方案一的寫法如下,先開啟事務支持 , 事務執行之后,再關閉事務支持 。
一次 Redis 事務使用不當引發的生產事故

文章插圖
但是這種寫法有個弊端,如果在執行 Redis 事務期間,在 @Transactional 注解的方法里面執行 Redis 命令,則還是會造成返回結果為 null 。
一次 Redis 事務使用不當引發的生產事故

文章插圖
4.2 方案二弄兩個 RedisTemplate Bean,一個是用來執行 Redis 事務的 , 一個是用來執行普通 Redis 命令的(不支持事務) 。不同的地方引入不同的 Bean 就可以了 。
先創建一個 RedisConfig 文件,自動裝配兩個 Bean 。一個 Bean 名為 stringRedisTemplate 代表不支持事務的,執行命令后立即返回實際的執行結果 。另外一個 Bean 名為 stringRedisTemplateTransaction,代表開啟 Redis 事務支持的 。
代碼如下所示:
一次 Redis 事務使用不當引發的生產事故

文章插圖
接下來在測試的 Service 類中注入兩個不同的 StringRedisTemplate 實例,代碼如下所示:
一次 Redis 事務使用不當引發的生產事故

文章插圖
Redis 事務的操作改寫成這樣,且不需要手動開啟 Redis 事務支持了 。用到的 StringRedisTemplate 是支持事務的那個實例 。
一次 Redis 事務使用不當引發的生產事故

文章插圖
在 Spring 的 @Tranactional 中執行的 Redis 命令如下所示,用到的 StringRedisTemplate 是不支持事務的那個實例 。
一次 Redis 事務使用不當引發的生產事故

文章插圖
然后還是按照上面場景 3 的測試步驟,先執行 testRedisMutil 方法,再執行 testTransactionAnnotations 方法 。
驗證結果:Redis 遞增操作正常返回 count 的值,修復完成 。
另外關于 Redis 事務使用還有一個坑 , 就是 Redis 連接未釋放,導致獲取不到連接了,這是下一個話題了~
參考資料:https://blog.csdn.net/qq_34021712/article/details/79606551
- END -
關于我8 年互聯網開發經驗 , 擅長微服務、分布式、架構設計 。目前在一家大型上市公司從事基礎架構和性能優化工作 。
InfoQ 簽約作者、藍橋簽約作者、阿里云專家博主、51CTO 紅人 。

推薦閱讀