java-@Transactional 事务注解


前言

在这里插入图片描述

一、什么是事务?

事务(Transactional) 就是把多个要做的操作组合成一个整体,利用事务的特性来保证操作的安全性,如果一个事务做到一半出现任何错误,就会进行回滚操作,来恢复成最初的模样。

二、事务的特性 (具有ACID的特性)

  1. A 原子性(atomicity) :
    事务是一个不可分割的工作单位,事务中的操作要么都修改,要么都不修改。
  2. C 一致性(consistency):
    事务在完成时,必须是所有的数据都保持一致状态。
  3. I 隔离性(isolation):
    一个事务的执行不能被其他事务所影响。
  4. D 持久性(Durability):
    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的。

三、@Transactional属性详解

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

  1. @Transactional 注解只能应用到接口方法、类、还有public方法上。
  2. 默认情况下,Spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。
    checked异常:Error或者RuntimeException(比如空指针,1/0)的异常;
    unchecked异常:继承自java.lang.Exception得异常统称为Checked Exception,如IOException、TimeoutException等。
  3. 只读事务:
    @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
    只读标志只在事务启动时应用,否则即使配置也会被忽略。
    启动事务会增加线程开销,数据库因共享读取而锁定(具体跟数据库类型和事务隔离级别有关)。通常情况下,仅是读取数据时,不必设置只读事务而增加额外的系统开销。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

四、注解失效问题

  1. @Transactional 应用在非 public 修饰的方法上
    事务拦截器在目标方法执行前后进行拦截,内部会调用方法来获取Transactional 注解的事务配置信息,调用前会检查目标方法的修饰符是否为 public,不是 public则不会获取@Transactional 的属性配置信息。

  2. @Transactional 注解属性 rollbackFor 设置错误
    rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定rollbackFor属性。

  3. 同一个类中方法调用,导致@Transactional失效
    开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。

那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。

  1. 异常被你的 catch“吃了”导致@Transactional失效
    如果你手动的catch捕获这个异常并进行处理,事务管理器会认为当前事务应该正常commit,就会导致注解失效,如果非要捕获且不失效,就必须在代码块内throw new Exception抛出异常。

  2. 数据库引擎不支持事务
    开启事务的前提就是需要数据库的支持,我们一般使用的Mysql引擎时支持事务的,所以一般不会出现这种问题。

  3. 开启多线程任务时,事务管理会受到影响
    因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。
    另外,使用多线程事务的情况下,进行回滚,比较麻烦。thread的run方法,有个特别之处,它不会抛出异常,但异常会导致线程终止运行。
    最麻烦的是,在线程中抛出的异常即使在主线程中使用try…catch也无法解释。这非常糟糕,我们必须要“感知”到异常的发生。比如某个线程在处理重要的事务,当thread异常终止,我必须要收到异常的报告,才能回滚事务。这时可以使用线程的UncaughtExceptionHandler进行异常处理,UncaughtExceptionHandler名字意味着处理未捕获的异常。更明确地说,它处理未捕获的运行异常。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里 Jess

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值