【JAVA事务】

1. spring事务管理简述

编码式事务管理:将事务控制代码编写在业务代码之中。
声明式事务管理:基于AOP(面向切面编程),事务管理与业务逻辑耦。
声明式事务管理的两种实现:
1.在配置文件(xml)中配置。
2.基于@Transactional注解。

2. 注解 @Transactional 的原理及应用

2.1 @Transactional注解的原理

![原理](https://img-blog.csdnimg.cn/2cfbeb5d5faf4ee7900f3437b580c630.png)
    原理总结:声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

@Transactional注解的逻辑是通过动态代理来实现的,而生成这个动态代理类分成了两步:
1、向spring容器注册事务相关的切面逻辑
2、根据切面逻辑生成动态代理
通过动态代理为标注了@Transactional注解的方法增加切面逻辑,而事务的上下文包括数据库链接都是通过ThreadLocal来传递,在这个切面逻辑里主要做这几个事情:
1、获取方法上标注的注解的元数据,包括传播级别、异常配置等信息
2、通过ThreadLocal获取事务上下文,检查是否已经激活事务
3、如果已经激活事务,则根据传播级别配置,看是否需要新建事务(如果新建事务,会生成一个新的事务上下文对象TransactionInfo,并将上一个事务上下文赋值到新上下文的oldTransactionInfo属性上代码位置在TransactionAspectSupport类的prepareTransactionInfo方法里的bindToThread方法里。
4、开启事务,先通过数据库连接池获取链接,关闭链接的auto commit,然后在try catch里反射执行真正的dao操作,通过异常情况来决定是commit还是rollback。

默认传播行为PROPAGATION_REQUIRED(如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。)
默认隔离级别与数据库一致,MySQL(可重复读)

2.2 @Transactional注解的应用:

1、添加位置
1、接口实现类或接口实现方法上,而不是接口类中。
@Transactional添加到类上,则表示此类的所有方法都开启事务管理。
@Transactional添加到方法上,则表示此方法开启事务管理。

2、访问权限public 的方法才起作用。@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。

3、只要出异常就回滚:
@Transactional注解中加上rollbackfor = Exception.class属性,默认回滚异常RuntimeException

4、@Transactional属性

5、类名上方使用 @Transactional,类中方法可通过属性配置来覆盖类上的 @Transactional 配置,比如:类上配置全局是可读写,可在某个方法上改为只读。

3.手工开启、提交、回滚 事务的方式

在这里插入图片描述

4.注解 @Transactional的跨库的事务处理

在这里插入图片描述
在这里插入图片描述

5.注解 @Transactional的跨数据源的事务处理

单源数据库,只要在需要进行事务控制的方法上添加@Transactional注解就可以,但是对于多源数据库,仅@Transactionnal是无法管理多个数据源的。
默认事务管理器:通过注解@primary
俩阶段协议:首先多个数据源的事务分别都开起来,然后各事务分别去执行对应的sql(此所谓第一阶段提交),最后如果都成功就把事务全部提交,只要有一个失败就把事务都回滚——此所谓第二阶段提交。
方法一、只使用主库事务管理器TransactionManger
@Transactional(value = “masterTransactionManager”),注解上使用value属性,注明是主库事务管理器
使用主库事务管理器,也就是说事务中产生异常时,只能回滚主库数据。但是因为数据操作顺序是先主后从,所以分一下三种情况:
主库插入时异常,主库未插成功,这时候从库还没来及插入,主从数据是还是一致的
主库插入成功,从库插入时异常,这时候在主库事务管理器监测到事务中存在异常,将之前插入的主库数据回滚,主从数据还是一致的
主库插入成功,从库插入成功,事务结束,主从数据一致。
当然这只是理想情况,假如存在一种情况,在数据库从库插入之后,还有其他业务逻辑的处理,假如这部分业务处理产生了异常,主库事务管理器只能回滚主库数据,但是从库数据是无法回滚的,这时候主从数据变产生了不一致。还有比如从库数据插入成功后,主库提交,这时候主库崩溃了,导致数据没插入,这时候从库数据也是无法回滚的。这种方式可以简单实现多源数据库的事务管理,但是无法处理上述情况。

方法二、为方法添加多个事务管理器
1、自定义注解
在这里插入图片描述
2、自定义AOP
在这里插入图片描述

3、添加注解和填写事务管理器
在这里插入图片描述

6.@Transactional失效的几种场景

1.内部方法自调用。一个有@Transactional的方法被没有@Transactional方法调用时,会导致Transactional作用失效。
原因:默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰
例如:
在这里插入图片描述
正确做法:
创建一个另外一个类TestB,放B方法,Test类加上@Transactional注解
在这里插入图片描述

2.对非public方法进行事务注解。@Transactional 将会失效。
原因:如下
在这里插入图片描述
3、捕获的异常没有被事务捕获。还存在一种情况:在一个类中A方法被事务注释,B方法也被事务注释。
@Transactional
public void A(){
  try{
  this.B();
  }catch(Exception e){
    logger.error();
  }

}
但在执行B方法是报错,但是异常被A catch 住,此时事务也会失效。

原因:在整个事务的方法中使用try-catch,导致异常无法抛出

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值