关于Spring事务的传播特性

摘要:Spring事务管理基于底层数据库本身的事务处理机制,对数据库事务操作的一次封装,相当于把使用JDBC代码开启、提交、回滚事务进行了封装。其传播特性共有七个

正文:

事务的传播特性

  1. Propagation.REQUIRED 方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,如果当前线程中已经存在事务, 方法调用会加入此事务, 如果当前没有事务,就新建一个事务。
  2. Propagation.REQUIRES_NEW 无论何时自身都会开启事务,这个事务不依赖于外部事务,它拥有自己的隔离范围,自己的锁,等等。当内部事务开始执行时,外部事务将被挂起,内部事务结束时,外部事务将继续执行。
  3. Propagation.SUPPORTS 自身不会开启事务,在事务范围内使用挂起事务,运行完毕不使用事务
  4. Propagation.NOT_SUPPORTED 自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务
  5. Propagation.MANDATORY 自身不会开启事务,必须在事务环境使用否则报错
  6. Propagation.NEVER 自身不会开启事务,在事务范围内使用抛出异常
  7. Propagation.NESTED 如果当前存在事务,则在嵌套的事务中执行,如果没有则按照TransactionDefinition.PROPAGATION_REQUIRED 属性执行。可以认为是已经存在事务的一个真正的子事务。嵌套事务开始执行时,它将取得一个 save point。如果这个嵌套事务失败,我们将回滚到此save point。嵌套事务是外部事务的一部分,只有外部事务结束后它才会被提交。 Propagation.REQUIRES_NEW和Propagation.NESTED 的最大区别在于,Propagation.REQUIRES_NEW完全是一个新的事务,而 Propagation.NESTED 则是外部事务的子事务。如果外部事务 commit,嵌套事务也会被 commit,这个规则同样适用于rollback。

测试代码

因为业务的需要,业务逻辑优先在单个Service中实现,同样为了保证数据的一致性需要使用事务,在单个Service中实现会出现嵌套事务。

如我们使用service C同时调用service A和service B ,如果service B抛出异常那么service C(外部事务)如果没有特殊配置(如异常时事务提交)那么整个事务是一定会rollback的。

测试代码: Service C: 如下代码所示,使用声明式注解@Transactional(rollbackFor=Exception.class)默认传播特性是Propagation.REQUIRED。

@Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRED)@Overridepublic int insert(Users users) throws Exception{ int i = users1Service.insert(users); int j = users2Service.insert1(users); return i+j;}

Controller层:

@RequestMapping(value = "/", method = RequestMethod.POST)public ResponseInfo postUser1(@RequestBody Users user) throws Exception { ResponseInfo resInfo = new ResponseInfo(); int i = usersService.insert(user); resInfo.setResponseInfo("users一共新增了" + i + "条数据"); return resInfo;}

Service A:

@Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)@Overridepublic int insert(Users users) throws Exception{ return usersMapper.insert(users);}

Service B:

@Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRED)@Overridepublic int insert1(Users users) throws Exception{ return usersMapper.insert1(users);}

根据以上代码可以通过测试两张表同时插入而一张表失败最后返回的数据进行分析: 本次使用Postman测试工具,数据库oracle 11g。 两张表其中一张age字段为number6位,一张为number2位,测试数据为三位,会有一张表插入失败,测试数据如下图所示。

结果是两张表都没有插入,如下图所示。

经过测试,说明嵌套事务与事务的传播特性有关,都使用默认的传播属性REQUIRED第一张插入后,第二张失败会导致外部事务(Service C)rollback,保证了数据的一致性。 若内部事务有使用REQUIRES_NEW属性,则会单独开一事务其运行结果不会影响外部数据会出现数据不一致。 若内部事务有使用NESTED属性,内部事务如果出现异常则会rollback到save point,从而外部事务可以使用try-catch进行分支执行(try里执行Service A,catch里执行Service B)。 查询语句应该设置为read-only,传播范围设置为NOT_SUPPORTED 如下代码所示:

/** * {@inheritDoc} * {@link newframe.business.demo.service.SecurityInfoService#queryAll()} * */ @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true) @Override public List<SecurityInfo> queryAll() throws MessageException { List<SecurityInfo> list = securityInfoMapper.queryAll(); return list; }

具体使用哪个属性根据业务来进行选择。

Spring注解

在项目中如果大量组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找不太方便。而注解可以很方便的标注完将其放入spring容器管理。

业务层注解 @Service:用于标注业务层组件。 @Controller:用于标注控制层组件。 @Repository:用于标注数据访问组件,即Dao组件。 @Component:泛指组件,不容易归类可以使用该组件。

Bean容器相关的注解 @Autowired:等同autowire=byType,根据类型的自动注入依赖。 @Qualifier:等同autowire=byName,当@Autowired注解需要判断多个 bean类型相同时,就需要使用@Qualifier(“xxBean”)来指定依赖的bean 的id。 @Resource:属于JSR250标准,作用同@Autowired,是属于byName类 型的依赖注入,使用方式:@Resource(name=”xxBean”),不带参数是默 认类名首字母小写。

@RequestBody:用于读取request请求的body部分数据(Json串或XML数据),将其转化为需要的对象。 @ResponseBody:将Controller的方法返回的对象通过适当的转换(通过配置可以返回Json或XML数据),写入response对象的body数据区。新框架可以在Controller里使用该注解返回Json数据。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

@Transactional导致AbstractRoutingDataSource动态数据源无法切换的解决办法

上午花了大半天排查一个多数据源主从切换的问题,记录一下: 背景: 项目的数据库采用了读写分离多数据源,采用AOP进行拦截,利用ThreadLocal及Abstr...

1.8K80
来自专栏aoho求索

基于可靠消息方案的分布式事务(二):Java中的事务

42560
来自专栏dalaoyang

SpringBoot使用WebFlux响应式编程操作数据库

在之前一篇简单介绍了WebFlux响应式编程的操作,我们在来看一下下图,可以看到,在目前的Spring WebFlux还没有支持类似Mysql这样的关系型数据库...

30210
来自专栏battcn

一起来学SpringBoot | 第一篇:构建第一个SpringBoot工程

未接触 SpringBoot 之前,搭建一个普通的 WEB 工程往往需要花费30分钟左右,如果遇到点奇葩的问题耽搁的时间会更长一点,但自从用了 SpringBo...

11210
来自专栏青玉伏案

JavaEE开发之记事本完整案例(SpringBoot + iOS端)

上篇博客我们聊了《JavaEE开发之SpringBoot整合MyBatis以及Thymeleaf模板引擎》,并且在之前我们也聊了《Swift3.0服务端开发(五...

23450
来自专栏耕耘实录

RHEL7.X系列及周边Linux发行版中,关于MBR与GPT的选择一些思考与建议

存储的选型、规划与管理等工作一直以来都是日常系统运维工作中的重点。MBR与GPT两种类型的分区表的选择与使用则是在磁盘管理中需要根据应用场景来注或考虑的要点。结...

13720
来自专栏java、Spring、技术分享

java 日志处理

  common-logging是 apache提供的一个通用的日志接口。用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的loggi...

45430
来自专栏JavaWeb

Spring 的编程式事务管理及声明式事务管理

34040
来自专栏乐沙弥的世界

基于Linux (RHEL 5.5) 安装Oracle 10g RAC

    本文所描述的是在Red Hat 5.5下使用vmware server 来安装Oracle 10g RAC(OCFS + ASM),本文假定你的RHEL...

16030
来自专栏IT笔记

SpringBoot开发案例之整合ActiveMQ实现秒杀队列

在实际生产环境中中,通常生产者和消费者会是两个独立的应用,这样才能通过消息队列实现了服务解耦和广播。因为此项目仅是一个案例,为了方便期间,生产和消费定义在了同一...

2.1K40

扫码关注云+社区

领取腾讯云代金券