[SpringBoot]SpringBoot中使用redis事务
本文基于SpringBoot 2.X
事务在关系型数据库的开发中经常用到,其实非关系型数据库,比如redis也有对事务的支持,本文主要探讨在SpringBoot中如何使用redis事务。
事务的相关介绍可以参考:
0、起因
在一次线上事故中,我们定位到redis的使用存在大value,超过了dubbo的最大数据量限制,于是紧急将这个大的对象value拆分成单个的string value。
为了保持数据库和redis双写一致,在对数据库进行更新,删除,插入操作时,要从redis删除指定的key。
一切都是使用redis的常规操作,但雷就埋在其中一个数据库的update方法里,这个方法上开启了事务@Transactional,导致里面的删除redis key操作也加入了事务。
上线后出现报错:

这个报错明确指出,集群模式的redis不支持事务。集群不支持事务的原因可参考此文:Is there any Redis client (Java prefered) which supports transactions on Redis cluster?
基于此次问题,总结出本文内容
1、Spring中的事务
所有数据访问技术都有事务机制,这些技术提供了API来开启事务、提交事务完成数据操作, 或者在发生错误的时候回滚数据。
Spring采用统一的机制来处理不同的数据访问技术的事务, Spring的事务提供一个PlatformTransactionManager的接口,不同的数据访问技术使用不同的接口实现。
| 数据访问技术 | 实现 |
|---|---|
| JDBC | DataSourceTransactionManager |
| JPA | JPATransactionManager |
| Hibernate | HibernateTransactionManager |
| JDO | JDOTransactionManager |
| 分布式事务 | JtaTransactionManager |
在SpringBoot中开启事务非常简单,只需要在方法或类上使用注解@Transactional即可。
Spring官方文档中还要求使用@EnableTransactionManagement 开启事务,但SpringBoot通过自动配置已经帮我们做了,所以SpringBoot中不用写该注解
这里重点讲下@Transactional注解的几个常用属性
propagation
事务的传播机制,主要有以下几种,默认是REQUIRED:
REQUIRED - 方法A调用时候没有事务新建一个事务,在方法A中调用方法B,将使用相同的事务,如果方法B发生异常需要回滚,整个事务回滚。

REQUIRES_NEW - 方法A调用方法B时,无论是否存在事务都开启一个新事务,这样B方法异常不会导致A的数据回滚。

NESTED - 和REQUIRES_NEW类似,但是只支持JDBC,不支持JPA或Hibernate
SUPPORTS - 方法调用时有事务就用事务,没事务就不用事务
NOT_SUPPORTED - 强制方法不在事务中执行,若有事务,在方法调用到结束阶段先挂起事务。
NEVER - 强制不能有事务,若有事务就抛出异常
MANDATORY - 强制必须有事务,如果没有事务就抛出异常
rollbackFor
指定哪些异常可以导致事务回滚,默认是Throwable的子类
noRollbackFor
执行哪些异常不可用引起事务回滚,默认是Throwable的子类
2、@Transactional事务失效的情况
- 只对public方法生效。默认的protected和private方法上写上@Transactional不会报错,但该方法上的事务不生效,官方原文:Method visibility and @Transactional;
- 默认情况(只写@Transactional不填写rollbackFor参数)下此注解会对unchecked异常进行回滚,对checked异常不回滚;
- 类内部未开启事务的方法调用开启事务的方法
前两条很好理解,针对3,引用丁雪丰的《Spring全家桶》视频中的解释:
Spring的声明式事务本质上是通过AOP来增强了类的功能
Spring的AOP本质上就是为类做了一个代理看似在调用自己写的类,实际用的是增强后的代理类
下图描述了方法被事务代理时的流程,来源:Spring AOP

3、SpringBoot整合Redis事务实践
下面我们搭建一个最简单的SpringBoot整合redis的工程用代码来验证redis事务
SpringBoot整合Redis
SpringBoot整合redis使用的是spring-boot-starter-data-redis,redis事务依赖于jdbc的事务管理,所以还需要引入jdbc
pom相关引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
开启Redis事务
编写redis配置类,开启redis事务,配置事务管理
@Configuration
public class RedisConfig {
@Bean
public StringRedisTemplate StringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
/**
* description 开启redis事务(仅支持单机,不支持cluster)
**/
template.setEnableTransactionSupport(true);
return template;
}
/**
* description 配置事务管理器
**/
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
代码验证
针对本文讨论,设计了四个验证方法,可自行验证
/**
* description 不带事务set
* return java.lang.String
* author 郑晓龙
* createTime 2019/12/12 16:36
**/
@GetMapping("put")
public void put(String key, String value) {
redisService.put(key, value);
}
/**
* description 带事务set
* return java.lang.String
* author 郑晓龙
* createTime 2019/12/12 16:36
**/
@GetMapping("putWithTx")
public void putWithTx(String key, String value) {
redisService.putWithTx(key, value);
}
/**
* description 调用带事务方法不生效的情况
* return java.lang.String
* author 郑晓龙
* createTime 2019/12/12 16:36
**/
@GetMapping("invokeWithPutTx")
public void invokeWithPutTx(String key, String value) {
redisService.invokePutWithTx(key, value);
}
/**
* description 调用带事务方法生效的情况
* return java.lang.String
* author 郑晓龙
* createTime 2019/12/12 16:36
**/
@GetMapping("invokeWithPutTx2")
public void invokeWithPutTx2(String key, String value) {
redisService.invokePutWithTx2(key, value);
}
4、总结:
- redis事务只支持单机,不支持cluster
- 需要开启事务时,只需要在对应的方法或类上使用@Transactional注解即可,SpringBoot自动开启了@EnableTransactionManagement
- 需要注意事务不生效的几种情况
- redis事务依赖于jdbc的事务管理
5、示例代码及参考:
- Transaction Management
- Transaction Propagation
- Transactional Support
- 《Spring全家桶》丁雪丰
欢迎扫码关注我的个人公众号,获取最新文章↓
[SpringBoot]SpringBoot中使用redis事务的更多相关文章
- Spring-Boot项目中配置redis注解缓存
Spring-Boot项目中配置redis注解缓存 在pom中添加redis缓存支持依赖 <dependency> <groupId>org.springframework.b ...
- SpringBoot项目中,Redis的初次使用
1.引入Redis依赖包,在application.yml中配置redis <dependency> <groupId>org.springframework.boot< ...
- Spring Framework 中启动 Redis 事务操作
背景: 项目中遇到有一系列对Redis的操作,并需要保持事务处理. 环境: Spring version 4.1.8.RELEASE Redis Server 2.6.12 (64位) spring- ...
- spring的声明式事务,及redis事务。
Redis的事务功能详解 http://ghoulich.xninja.org/2016/10/12/how-to-use-transaction-in-redis/ MULTI.EXEC.DISCA ...
- 由浅入深学习springboot中使用redis
很多时候,我们会在springboot中配置redis,但是就那么几个配置就配好了,没办法知道为什么,这里就详细的讲解一下 这里假设已经成功创建了一个springboot项目. redis连接工厂类 ...
- 在SpringBoot中引入Redis
前言 之前我们只是在Spring中加入Redis用于session的存放,并没有对redis进行主动的存放,这次我们需要加入redis工具类来方便我们在实际使用过程中操作redis 已经加入我的git ...
- SpringBoot中集成redis
转载:https://www.cnblogs.com/zeng1994/p/03303c805731afc9aa9c60dbbd32a323.html 不是使用注解而是代码调用 需要在springbo ...
- (一)由浅入深学习springboot中使用redis
很多时候,我们会在springboot中配置redis,但是就那么几个配置就配好了,没办法知道为什么,这里就详细的讲解一下 这里假设已经成功创建了一个springboot项目. redis连接工厂类 ...
- SpringBoot中使用Redis
在SpringBoot中使用Redis,思路如下: 查询时先查Redis缓存,如果缓存中存在信息,就直接从缓存中获取. 如果缓存中没有相关信息,就去数据库中查找,查完顺便将信息存放进缓存里,以便下一次 ...
随机推荐
- KVM NAT(网络地址转换模式)
NAT(网络地址转换模式) 使用NAT模式,就是让虚拟系统借助NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网.也就是说,使用NAT模式可以实现在虚拟系统里访问互联网.很显然,如果你只有一 ...
- 由软件构造引申的OOP与POP的心得体会
在大一初学C语言的时候,所解决的问题都是一些轻量级的简单问题,当时写过一个教学管理系统.这个教学管理系统的功能很简单,思想就是“流水线”:按部就班的实现所有流程.要完成整个教学管理系统,实际上就是完成 ...
- 日期时间设置 QDate, QTime, QDateTime
#!/usr/bin/python3 from PyQt5.QtCore import QDate, QTime, QDateTime, Qt now = QDate.currentDate() pr ...
- 时间序列神器之争:prophet VS lstm
一.需求背景 我们福禄网络致力于为广大用户提供智能化充值服务,包括各类通信充值卡(比如移动.联通.电信的话费及流量充值).游戏类充值卡(比如王者荣耀.吃鸡类点券.AppleStore充值.Q币.斗鱼币 ...
- ubuntu12.04 empathy添加qq登陆
1,
- @atcoder - AGC034F@ RNG and XOR
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个值域在 [0, 2^N) 的随机数生成器,给定参数 A[ ...
- 有没有人想和我一起编写 Clear Writer 的?
合作内容 程序编写 了解 JS.HTML.CSS 等基础前端技能,了解 Electron 开发. 翻译 熟练运用一门外语(中文英文除外),书面表达过关. 报酬 在 Github 上本项目里面的 REA ...
- 14.Django-JWT
一.基于JWT的Token登录认证 1. JWT简介 json Web Token(缩写JWT)是目前最流行的跨域认证解决方案 session登录的认证方案是看,用户从客户端传递用户名和密码登录信息, ...
- 十六进制颜色码及其表示-(6 digit color code)
我们知道对于RGB颜色系统,颜色是由三个256位的十进制数值表示的: (R:0-255,G:0-255,B:0-255) 那么一个三元组可以确定一种颜色. 然而,在很多配置文件中颜色并不是直接用十进制 ...
- 这一次搞懂SpringMVC原理
@ 目录 前言 正文 请求入口 组件初始化 调用Controller 参数.返回值解析 总结 前言 前面几篇文章,学习了Spring IOC.Bean实例化过程.AOP.事务的源码和设计思想,了解了S ...