为了账号安全,请及时绑定邮箱和手机立即绑定

【学习打卡】第15天 Spring事务学习

标签:
Spring

课程名称Java架构师-技术专家
课程章节:第1周 架构初知与单体架构设计
主讲老师:慕课讲师团:Geely、风间影月、阿神……

课程内容:

Spring 声明式事务 @Transactional 注解

  • @Transactional 是 Spring 事务管理提供的注解,在一个方法中加上了这个注解,那么这个方法就是有事务的,方法内的操作要么一起提交,要么回滚。

Propagation

事务的传播行为,表示被调用者的事务和调用者的事务之间的关系。

表示当一个事务传播行为修饰的方法被另一个方法调用时,事务如何进行传播。不同的 propagation 配置会有不同的效果

  1. methodB 是事务修饰的方法
  2. methodA 调用了 methodB ,那么事务应该如何传播呢?

:::tip
99% 的情况下都使用 Propagation.REQUIRED
:::

1. 默认传播行为:Propagation.REQUIRED

  • 支持当前事务;如果当前没有事务,则新建一个事务。(日常开发中最常使用的配置)

2. Propagation.REQUIRE_NEW

  • 新建事务;如果当前存在事务,则把当前事务挂起
  • 由于 methodA、methodB 它们的方法使用是两个不同的事务,当 methodB 方法提交后,即使 methodA 方法失败回滚了,
    也不会导致 methodB 方法出现回滚;当 methodB 方法失败回滚以后,如果methodA未捕捉到methodB抛出的异常,
    导致methodA 继续抛出该异常,methodA方法也会被回滚,如果methodA方法捕获了methodB方法所抛出的异常,则methodA所在的事务还是有可能提交成功的,因为当前的事务已经被挂起了。

3. Propagation.SUPPORTS

  • 支持当前事务;否则将以非事务方式执行

4. Propagation.MANDATORY

  • 支持当前事务;如果没有将抛出 IllegalTransactionStateException 异常
  • 会打断 methodA 方法的执行,除非在 methodA 方法中捕获并处理这个异常。

5.Propagation.NOT_SUPPORT

  • 不支持当前事务,而是始终以非事务的方式执行

6. Propagation.NEVER

  • 以非事务的方式执行;如果当前存在事务,则抛出 IllegalTransStateException 异常
  • 要求调用者方法不存在事务注解,很少使用

7. Propagation.NESTED

  • 如果当前存在事务,则对于该传播行为修饰的方法会依然使用当前事务
  • 基本上不会使用到

isolation

事务的隔离级别,决定了事务的完整性,默认使用当前数据库默认的隔离级别,通常不会去修改这个属性,

timeout

事务的过期时间或者超时时间,默认是当前数据库默认的过期时间或者超时时间,通常不需要额外定制,使用数据库的即可。

readOnly

指定是否为只读事务,默认是 false ,如果在一次执行单条查询语句,则没有必要启用事务支持,数据库默认启用 SQL 执行期间的读一致性。

如果一次执行多条查询语句,比如统计查询,报表查询;在这种场景下,多条查询的 SQL 必须保证整体的一致性,否则在前一条SQL查询之后,后一条 SQL 查询之前,数据被其它用户改变,这次整体的统计查询将会出现读
数据不一致的状态,此时应该启用只读事务的支持。

对于只读查询,可以指定事务类型为 readOnly, 由于只读事务不存在数据的修改,所以数据库将为只读事务添加一些优化手段。

rollbackFor、noRollbackFor

rollbackFor 指定那些异常会导致事务回滚。

noRollbackFor 指定那些异常不会导致事务回滚。

@Transactional 注解默认只针对 RuntimeException 、Error 及其子类进行回滚,如果希望对检查型的异常进行回滚就需要对 rollbackFor 属性进行配置。

noRollbackFor 属性正好相反,用于指定那些异常不发生回滚。

@Transactional 注解最常见的应用

  • 可以标注在类、方法和接口(但接口上会失效,所以不能这样用)上;且方法上的注解会覆盖类上的注解
  • 标注在方法上,标识开启事务功能,正常则提交、异常则回滚
  • 自行指定rollbackFor属性,让Checked Exception 也能够实现回滚
  • 让 TestCase 也能够实现回滚(只需要在测试方法上面加上注解)。如果已经有了 @Transactional 注解在类上面。但是,还是想要不回滚某个单元测试,加上 @Rollback(value=false)

@Transactional注解失效的场景

场景一: 把注解标注在非 public 修饰的方法上

把注解标注在非 public 修饰的方法上,SpringAOP 代理时,最终会调用一个方法(TransactionalRepositoryProxyPostProcessor#AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class<?> targetClass))去计算注解的属性是否符合要求,这个方法的第一行就是去检查方法是不是 public 的,如果不是则不能获取 @Transactional 注解的配置信息。虽然事务没有生效,但是编译运行代码不会有任何错误。
java private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { if (this.allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } }

场景二:propagation(传播行为)属性配置错误

  • Propagation.SUPPORTS: 如果调用方没有事务,那么会以非事务的方式运行。
  • Propagation.NOT_SUPPORTS : 会挂起当前事务,那么会以非事务的方式运行
  • Propagation.NEVER: 如果有事务,会抛出异常

场景三:rollbackFor属性设置错误

rollbackFor 能够指定触发事务回滚的异常类型,Spring默认抛出了非检查型的异常或者是Error 才会回滚事务。如果在事务中抛出了其它类型的异常,但却希望Spring能够回滚事务就需要自己指定 rollbackFor属性

场景四:在同一个类中方法调用,导致事务失效

比如有一个类有两个方法 methodA 和 methodB,methodA 去调用类里面的 methodB ,不管 methodB 的访问修饰符是什么,如果 methodA 没有声明注解事务,而 methodB 有 ,则 外部调用 methodA 以后,
methodB 的事务是不会起作用的。

只有事务方法被当前类以外的代码调用的时候,才会由 Spring 生成的代理对象去管理

场景五:自己主动去catch,代表 【没有异常】,导致事务失效

场景六:数据库引擎本身就不支持事务(例如 MyISAM),当然也不会生效

事务从根本上就失效了,因为 Spring 也要依赖基础设施。

学习收获:

今天详细学习了Spring的事务

  1. 事务的传播特性,
  2. 事务的rollbackFor等属性
    图片描述

图片描述

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
6
获赞与收藏
11

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消