[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缓存,如果缓存中存在信息,就直接从缓存中获取. 如果缓存中没有相关信息,就去数据库中查找,查完顺便将信息存放进缓存里,以便下一次 ...
随机推荐
- zabbix 大流量断图
一. 环境介绍 系统版本:Centos7.4 zabbix-agent 版本:zabbix-agent 3.4.7 二. 问题现象 在使用zabbix的snmp方式的监控端口流量时,某一个图总是断 ...
- AsyncTask源码解读
AsyncTask源码解读 一.基本使用 protected void onPreExecute() protected abstract Result doInBackground(Params.. ...
- PBFT共识算法
拜占庭将军问题 我们已知的共识算法,Paxos.Raft解决的都是非拜占庭问题,也就是可以容忍节点故障,消息丢失.延时.乱序等,但节点不能有恶意节点.但如何在有恶意节点存在的情况下达成共识呢?BFT共 ...
- 时间序列神器之争:prophet VS lstm
一.需求背景 我们福禄网络致力于为广大用户提供智能化充值服务,包括各类通信充值卡(比如移动.联通.电信的话费及流量充值).游戏类充值卡(比如王者荣耀.吃鸡类点券.AppleStore充值.Q币.斗鱼币 ...
- vue2.0 + Element UI + axios实现表格分页
注:本文分页组件用原生 html + css 实现,element-ui里有专门的分页组件可以不用自己写,详情见另一篇博客:https://www.cnblogs.com/zdd2017/p/1115 ...
- fopen函数中的mode参数
fopen FILE * fopen ( const char * filename, const char * mode ); 其中,参数mode可取以下值: "r"read: ...
- 数据结构之栈(Stack)
什么是栈(Stack) 栈是一种遵循特定操作顺序的线性数据结构,遵循的顺序是先进后出(FILO:First In Last Out)或者后进先出(LIFO:Last In First Out). 比如 ...
- (八)利用 Profile 构建不同环境的部署包
接上回继续,项目开发好以后,通常要在多个环境部署,象我们公司多达5种环境:本机环境(local).(开发小组内自测的)开发环境(dev).(提供给测试团队的)测试环境(test).预发布环境(pre) ...
- Linux服务器安装python3.6
CentOS 7上默认安装的python版本是2.7.5,系统自带的旧版本python被系统很多其他软件环境依赖,因此不能卸载原Python,直接选择Python3.6.5进行全新安装. 1 安装Py ...
- phpmyadmin系列渗透思路连载(一)
当拿到phpmyadin的站点后,我一般会尝试一下几种攻击手法: 1.通过弱口令进入后台,尝试into outfile写入一句话 条件:(1)有写的权限 (2)知道web绝对路径 (3)w ...