Spring事务管理

Spring事务管理

什么是事务?

事务指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败。

事务的四大特性(ACID)

  • 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  • 一致性(Consistency):事务开始前和结束后,数据的完整性约束没有被破环。比如A向B转了钱,转账前后钱的总数不变。
  • 隔离性(Isolation):多个用户并发访问数据数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间的数据相互隔离。比如事务A和事务B都修改同一条记录,这条记录就会被重复修改或者后者会覆盖前者的修改记录。
  • 持久性(Durability):事务完成后,事务对数据库的更新被保存到数据库,其结果是永久的。

事务并发可能产生的问题

脏数据:事务对缓冲池中的行记录进行修改,但是还没有被提交。

  • 脏读:事务A读取到了事务B修改但未提交的数据。如果此时B回滚到修改之前的状态,A就读到了脏数据。
  • 不可重复读:事务A多次读取同一个数据,此时事务B在A读取过程中对数据修改并提交了,导致事务A在同一个事务中多次读取同一数据而结果不同。
  • 幻读:事务A对表进行修改,这个修改涉及到表中所有的行,但此时事务B新插入了一条数据,事务A就会发现居然还有数据没有被修改,就好像发生幻觉一样。

事务隔离级别

TransactionDefinition接口中定义了事务的隔离级别和传播行为等参数。

为了应对不同的事务问题,有了如下几种事务隔离级别。

隔离级别 含义
DEFAULT 使用后端数据库默认的隔离级别
READ_UNCOMMITTED 允许读取未提交的数据,可能导致脏读、不可重复读、幻读
READ_COMMITTED 允许并发事务提交后读取,可能导致不可重复读、幻读。
REPEATABLE_READ 在同一次事务中对相同字段的多次读取结果一致,除非数据本身被改变。可防止脏读和不可重复读,但依然存在幻读的可能
SERIALIZABLE 不会发生 脏读、不可重复读、幻读等问题。隔离级别最高,但是并发下效率低,一般是通过锁表来实现的。

事务的传播行为

推荐阅读这篇博客,以下关于事务传播行为的内容均出自于该篇博客。

事务传播行为类型 说明
REQUIRED 如果已经存在一个事务中,加入到这个事务中;如果当前没有事务,就新建一个事务。Spring的默认传播行为
SUPPORTS 如果已经存在一个事务中,加入到这个事务中;如果当前没有事务,就以非事务方式执行。
MANDATORY 如果已经存在一个事务中,加入到这个事务中;如果当前没有事务,就抛出异常
REQUIRES_NEW 如果当前存事务,将当前事务挂起不使用,新建一个事务
NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,并且实现者需要支持保存点事务机制。有时候业务比较复杂,经常可能有service之间互相调用的情况发生,比如下面:

ForumSerivce#addTopic()方法调用了 UserSerice#addCredits()方法,发生关联性服务方法的调用:

public class ForumService {

private UserService userService;

public void addTopic() {

    // 被关联调用的业务方法
    userService.addCredits();
    
}

}

当事务隔离级别是REQUIRED、SUPPORTS、MANDATORY时,都是将事务加入到已经存在的事务中。因此将ForumService#addTopic()设置为REQUIRED时, UserSerice#addCredits()设置为REQUIRED、SUPPORTS、 MANDATORY时,运行的效果都是一致的。

当addTopic()运行在一个事务下(如设置为REQUIRED),而addCredits()设置为NESTED时,如果底层数据源支持保存点,Spring将为内部的addCredits()方法产生的一个内嵌的事务。如果 addCredits()对应的内嵌事务执行失败,事务将回滚到addCredits()方法执行前的点,并不会将整个事务回滚。内嵌事务是内层事务的一 部分,所以只有外层事务提交时,嵌套事务才能一并提交。

嵌套事务不能够提交,它必须通过外层事务来完成提交的动作,外层事务的回滚也会造成内部事务的回滚。

REQUIRES_NEW 和NESTED也是容易混淆的两个传播行为。

REQUIRES_NEW启动一个新的、和外层事务无关的“内部”事务。该事务拥有自己的独立隔离级别,不依赖于外部事务,独立地提交和回滚。当内部事务开始执行时,外部事务 将被挂起,内务事务结束时,外部事务才继续执行。

由此可见,NEW 和 NESTED 的最大区别在于:REQUIRES_NEW 将创建一个全新的事务,它和外层事务没有任何关系,而NESTED 将创建一个依赖于外层事务的子事务,当外层事务提交或回滚时,子事务也会连带提交和回滚。

事务的状态

TransactionStatus接口中有一些方法可以查询事务的状态。

// 该事务是否是一个新事务
boolean isNewTransaction();
// 该事务是否有保存点
boolean hasSavepoint();
// 设置仅事务回滚。这指示事务管理的唯一可能结果是回滚,作为抛出异常的替代方法,而异常又会触发回滚。
void setRollbackOnly();
// 是否被设置了rollback-only
boolean isRollbackOnly();
// 将潜在的会话(underlying session)刷新到数据库中
void flush();
// 事务是否已经完成
boolean isCompleted();

PlatformTransactionManager

PlatformTransactionManager(平台事务管理器)

Spring为不同的持久化框架提供了不同的PlatformTransactionManager接口实现。

image

事务的使用

在Spring Boot中,声明事务很简单。只需要在service层的类或者方法上加上@Transactional注解即可,省去了繁琐的配置。在service类上加@Transactional,声明这个service所有方法需要事务管理。每一个业务方法开始时都会打开一个事务。

@Transactional
public void transfer(AccountA a, AccountB a, Double money) {
    a.subtract(100.0);
    b.add(100.0);
}

@Transactional可以配置如下属性

  • transactionManager,可以指定具体的PlatformTransactionManager
  • propagation,传播行为,默认是REQUIRED
  • isolation,隔离级别,默认是DEFAULT(使用后端数据库默认的隔离级别)
  • timeout,设置超时时间(秒),超时后会回滚事务。默认值-1。
  • readOnly,该属性用于设置当前事务是否为只读事务,默认值为false。
  • rollbackFor,该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。
  • noRollbackFor,该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚
  • rollbackForClassName,该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。
  • noRollbackForClassNam,该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚

Spring默认情况下会对运行时异常(RunTimeException)进行事务回滚,这些异常属于非受检异常。比如ArrayIndexOutOfBoundsException,NullPointerException;但不会对受检异常进行事务回滚,这些异常包括:ClassNotFoundException、NoSuchMetodException等。若要对所有异常都进行事务回滚,可以如下设置。

@Transactional(rollbackFor=Exception.class)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,504评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,898评论 1 300
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,218评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,322评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,693评论 3 290
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,812评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,747评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,476评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,700评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,190评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,541评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,206评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,129评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,903评论 0 199
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,894评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,748评论 2 274

推荐阅读更多精彩内容

  • 事物的特性(ACID) 我们在使用JDBC或者Mybatis进行数据持久化操作时,我们的xml配置通常如下: 并发...
    Y了个J阅读 1,161评论 0 1
  • 1 什么是事务 生活中关于事务有一个常见的场景,即银行用户转账。简单的讲,转账可以分为下面 2 个步骤: 查看用户...
    millions_chan阅读 594评论 0 4
  • 事务简介 所谓事务,指的是程序中可运行的不可分割的最小单位。在生活中事务也是随处可见的。比方说你在Steam上剁手...
    乐百川阅读 660评论 0 5
  • Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,...
    EnigmaXXX阅读 649评论 0 0
  • 概要:2Spring事务管理接口(隔离级别,传播行为)、3接口介绍、4回滚原理 Spring事务的本质其实就是数据...
    hedgehog1112阅读 629评论 0 0