建设银行么官方网站,wordpress网站基础知识,阿里域名官网,青岛做网站本文基于SpringBoot 2.X 事务在关系型数据库的开发中经常用到#xff0c;其实非关系型数据库#xff0c;比如redis也有对事务的支持#xff0c;本文主要探讨在SpringBoot中如何使用redis事务。 事务的相关介绍可以参考#xff1a; 0、起因 在一次线上事故中#xff0c;我们… 本文基于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的接口不同的数据访问技术使用不同的接口实现。
数据访问技术实现JDBCDataSourceTransactionManagerJPAJPATransactionManagerHibernateHibernateTransactionManagerJDOJDOTransactionManager分布式事务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相关引入 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId
/dependency
dependencygroupIdcom.h2database/groupIdartifactIdh2/artifactIdscoperuntime/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 ManagementTransaction PropagationTransactional Support《Spring全家桶》丁雪丰