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 {@Beanpublic StringRedisTemplate StringRedisTemplate(RedisConnectionFactory factory) {StringRedisTemplate template = new StringRedisTemplate(factory);/*** description 开启redis事务(仅支持单机,不支持cluster)**/template.setEnableTransactionSupport(true);return template;}/*** description 配置事务管理器**/@Beanpublic 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、示例代码及参考:
示例代码: redis-transaction
- Transaction Management
- Transaction Propagation
- Transactional Support
- 《Spring全家桶》丁雪丰
SpringBoot中使用redis事务相关推荐
- Springboot 中的Redis 事务使用
简述 有一些场景我们可以在一段代码中多次操作redis,每次请求Redis都要去Jedis/Lettuce连接池申请一个连接请求一次redis服务进行缓存操作. 这样不仅有网络的消耗,假如在redis ...
- springboot中使用redis详解
一.redis简介 redis是一款高性能key-value(键值对)内存型数据库,是非关系型数据库的一种,它采用单线程的架构方式,避免了多线程存在的锁处理造成的资源耗费,读取速度非常快,非常适合变化 ...
- Docker中搭建redis分片集群,搭建redis哨兵结构,实现springboot中对redis分片集群、哨兵结构的访问,Redis缓存雪崩、缓存击穿处理(非关系型数据库技术课程 第十二周)
文章目录 一.要求: 二.知识总结 缓存雪崩 解决方案 docker中redis分片集群搭建 配置好配置文件 redis-6380.conf redis-6381.conf redis-6382.co ...
- 你知道如何在springboot中使用redis吗
特别说明:本文针对的是新版 spring boot 2.1.3,其 spring data 依赖为 spring-boot-starter-data-redis,且其默认连接池为 lettuce ...
- SpringBoot中集成Redis实现对redis中数据的解析和存储
场景 SpringBoot中操作spring redis的工具类: SpringBoot中操作spring redis的工具类_霸道流氓气质的博客-CSDN博客 上面讲的操作redis的工具类,但是对 ...
- SpringBoot中使用Redis保存对象或集合
1,引入SpringBoot中Redis依赖 <!-- redis --> <dependency><groupId>org.springframework.boo ...
- redis:01入门指南以及在springboot中使用redis
https://redis.io/download step1:参考官网的安装很简单 wget http://download.redis.io/releases/redis-5.0.6.tar.gz ...
- SpringBoot中Service层事务控制
SpringBoot中使用事务比较简单,在Application启动类上添加@EnableTransactionManagement注解,然后在service层的方法上添加@Transactional ...
- java中关闭redis事务_Redis 事务支持
原标题:Redis 事务支持 Redis 事务支持 Redis中事务相关的命令有MULTI.EXEC.DISCARD.WATCH和UNWATCH. Redis事务保证原子性:要么所有命令都执行(都执行 ...
最新文章
- python爬虫知识点总结(二十三)Scrapy中Download Middleware的用法
- C++ 虚函数和纯虚函数的用法
- NET Framework 2.0中的数据访问新特性
- 提示YOU DON'T HAVE PERMISSION TO ACCESS / ON THIS的解决方法
- other-如何可以查看别人请求的输出结果
- 关于微信小程序swiper的问题
- R语言快速学习第二部分(有其他语言基础)
- 基于JAVA+SpringMVC+Mybatis+MYSQL的实验室设备管理系统
- 编程语言对比 异常处理
- Navicat 创建mysql事件
- 修改lgoin,http://www.tuicool.com/articles/U3iyqq
- jQuery:基础知识学习
- canvas实现5张图片合成一张图片
- Ubuntu12.10 使用DNW传数据 进行ARM开发板烧写
- 8086指令系统中的寻址方式
- 原生JS实现球面展示特效
- 代码:骨骼提取,原图匹配,Matlab
- memcached的基础
- ARM嵌入式体系架构(理论篇)
- Build and participate in multiple QQ groups to communicate SharePoint technology