最近看到Medium上一篇讨论Spring Framework中事务传播的文章,解释了几种常见的问题,解释的不错,这里直接翻译吧(意译为主,粗体和斜体是我自己加上的)。

译文:

这是我的第一篇文章,我打算给大家总结一下开发者在使用Spring事务时,常常会犯的和事务传播相关的错误。

在这之前,我们先回忆一下Spring中事务是怎样传播的。

我们先看下Ken Tousen做的有关事务传播注解的笔记(译注:这里指@Transactional注解的propagation属性),这会帮助我们更清楚地记忆。

1. 私有方法

当公有方法调用私有方法时,不会创建新事务。(译注:这里有点问题,见下面评论)

 @Transactional
public class MusicPlayerService { @Autowired
Song song; @Autowired
MusicCatalogueService musicCatalogueService; public void playSong() {
scrobble();
song.play();
} @Transactional(propagation = Propagation.REQUIRES_NEW)
private void scrobble() {
musicCatalogueService.scrobble(song);
}
}

上面这个例子里,如果musicCatalogueService.scrobble(song)调用失败了,playSong()也会失败。

因为playSong()和scrobble()在同一个事务中。

所以要开启新事务,方法必须声明为public。

译注:

这里有点问题。即使将scrobble()声明为public,scrobble()也不会开启新事务。

这是因为Spring是使用AOP来进行事务管理的。而scrobble()和playSong()在一个类里,当playSong()调用scrobble()时,是直接调用scrobble()而不是调用代理方法,所以这两个方法都在同一个事务中。而musicCatalogueService.scrobble(song)是另一个对象(musicCatalogueService)中的方法,这个对象由Spring注入,是可以通过AOP代理的,也就可以通过注解开启新事务(当然前提是,musicCatalogueService的方法有注解)。

小结:

(1)@Transactional注解对私有方法不起作用,只对公有方法生效。

(2)Spring使用AOP进行事务管理,因此同一个类中的方法互相调用,在不涉及其他类的方法时,如果第一个方法开启了事务,那么接下来所有的方法都处于同一个事务中(不论其他方法是否私有/公有、是否有注解、注解的传播级别是什么)。

(3)只有调用不同类的方法时,才有可能开启新事务。

2. 同一个类中的方法调用

如果一个方法调用另一个方法,而这个被调用方法要开启新事务的话,它必须在另一个类中。

不然,这两个方法在同一个事务中。

把方法放在不同的类中来开启新事务的例子:

 @Transactional
public class MusicPlayerService { @Autowired
Song song; @Autowired
MusicCatalogueService musicCatalogueService; public void playSong() {
musicCatalogueService.scrobble(song);
song.play();
}
} public class MusicCatalogueService { @Autowired
ScrobbleRepository scrobbleRepository; @Transactional(propagation = Propagation.REQUIRES_NEW)
public void scrobble(Song song) {
scrobbleRepository.save(song);
}
}

3. SUPPORTS和readonly结合

如果没有正在进行的事务,那么SUPPORTS不会创建新事务。readonly会被忽视。

4. CRD操作和readonly结合

如果我们使用了REQUIRED或者REQUIRES_NEW,以及readonly,然后尝试做CREATE/DELETE/UPDATE操作,那么程序会抛出只读异常。

5. Checked Exceptions

如果程序抛出RuntimeException,事务会回滚。这很合理。

但是如果程序抛出的是checked exceptions呢?

答案是:事务不会回滚。

那怎样去处理这种情况?

Spring提供了rollbackFor属性。通过指定要回滚的异常类型,可以确保在程序抛出checked exceptions时事务回滚。用法如下:

@Transactional(rollbackFor = Exception.class)
public void rollBackActionDefinedMethod() {
}

译文完。

Spring Framework中常见的事务传播陷阱(译文)的更多相关文章

  1. Spring Framework 中启动 Redis 事务操作

    背景: 项目中遇到有一系列对Redis的操作,并需要保持事务处理. 环境: Spring version 4.1.8.RELEASE Redis Server 2.6.12 (64位) spring- ...

  2. 事务特性,事务的隔离级别以及spring中定义的事务传播行为

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  3. 转-Spring Framework中的AOP之around通知

    Spring Framework中的AOP之around通知 http://blog.csdn.net/xiaoliang_xie/article/details/7049183 标签: spring ...

  4. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->Spring Framework中的spring web MVC模块

    spring framework中的spring web MVC模块 1.概述 spring web mvc是spring框架中的一个模块 spring web mvc实现了web的MVC架构模式,可 ...

  5. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->Spring Framework中web相关的知识(概述)

    Spring Framework中web相关的知识 1.概述: 参考资料:官网documentation中第22小节内容 关于spring web mvc:  spring framework中拥有自 ...

  6. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->关于spring framework中的beans

    Spring framework中的beans 1.概述 bean其实就是各个类实例化后的对象,即objects spring framework的IOC容器所管理的基本单元就是bean spring ...

  7. Spring支持的常用数据库事务传播属性和隔离级别

    事务的四大特征:原子性,隔离性,持久性,一致性 spring提供了7种事务传播属性: 一个事务与其他事务的隔离程度称为隔离级别.不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性 ...

  8. 实例详解 EJB 中的六大事务传播属性--转

    前言 事务 (Transaction) 是访问并可能更新数据库中各种数据项的一个程序执行单元 (unit).在关系数据库中,一个事务可以是一条或一组 SQL 语句,甚至整个程序.它有通常被称为 ACI ...

  9. 在Spring Boot中使用数据库事务

    我们在前面已经分别介绍了如何在Spring Boot中使用JPA(初识在Spring Boot中使用JPA)以及如何在Spring Boot中输出REST资源(在Spring Boot中输出REST资 ...

随机推荐

  1. 重温ASP.NET WebAPI(一)初阶

    重温ASP.NET WebAPI(一)初阶   前言 本文为个人对WebApi的回顾无参考价值.主要简单介绍WEB api和webapi项目的基本结构,并创建简单地webaapi项目实现CRUD操作. ...

  2. LeetCode OJ:Jump Game II(跳跃游戏2)

    Given an array of non-negative integers, you are initially positioned at the first index of the arra ...

  3. LeetCode OJ:Power of Two(2的幂)

    Given an integer, write a function to determine if it is a power of two. 看一个数是不是2的幂,代码如下: class Solu ...

  4. 【HTML5】HTML5 WebSocket简介以及简单示例

    互联网发展到现在,早已超越了原始的初衷,人类从来没有像现在这样依赖过他:也正是这种依赖,促进了互联网技术的飞速发展.而终端设备的创新与发展,更加速了互联网的进化: HTTP/1.1规范发布于1999年 ...

  5. elasticsearch关于索引切分的实现

    [背景信息] ES一直以来对于已经创建好的索引的分片是不可以进行分割的,简单的说,当你创建了一个索引,并指定了number_of_shards为2,当随着数据量的不断增大,是无法将索引的shard扩充 ...

  6. (一) ffmpeg filter学习-使用流程

    FFMPEG中有一个类库:libavfilter.该类库提供了各种视音频过滤器.之前一直没有怎么使用过这个类库,最近看了一下它的使用说明,发现还是很强大的,有很多现成的filter供使用,完成视频的处 ...

  7. 【Hibernate实战】源码解析Hibernate参数绑定及PreparedStatement防SQL注入原理

        本文采用mysql驱动是5.1.38版本. 本篇文章涉及内容比较多,单就Hibernate来讲就很大,再加上数据库驱动和数据库相关,非一篇文章或一篇专题就能说得完.本文从使用入手在[Spr ...

  8. RMI垃圾收集简介

    和单机系统类似, 分布式系统也需要自动清除不再有客户端引用的对象(remote object). 远程对象的自动垃圾回收机制, 将程序员从深坑中解放出来, 不再需要人工跟踪client所引用的对象了. ...

  9. Python如何输出带颜色的文字

    print('\033[31m%s' % "这是前景色") 这是前景色 print('%s' % "这是前景色") 这是前景色 print('\033[1;31 ...

  10. postfix邮件服务器搭建01-准备篇

    本系列文章主要介绍linux下主流的开源邮件系统postfix的搭建过程,构建一个通过postfix虚拟用户管理的完整的邮件系统, 该系统包括以下组件: 邮件收发端postfix,dovecot, 邮 ...