同学~你了解@Transactional注解吗?

  • 你在项目中是如何使用事物的?
我们项目的框架都是使用的Spring,spring分为 编程式事务,在代码中硬编码。声明式事务,
在配置文件中配置(推荐使用)
声明式事务又分为两种:基于XML的声明式事务基于注解的声明式事务。
我一般都是通过注解来进行的事务控制。也就是@Transactional
  • 能先简单介绍一下@Transactional注解吗?项目中如何使用的?有哪些注意点吗?
我们都是把注解加到需要使用事务控制的方法上,也可以加到类上,加到类上是给类里的所有的方法都加了事务,
不建议这样做,这样会增加不需要使用事务的接口的响应时长。
@Transactional注解只能用在public 方法上,如果用在protected或者private的方法上,不会报错,
但是该注解不会生效。
@Transactional注解只能回滚非检查型异常,具体为RuntimeException及其子类。
  • Spring 事务中的隔离级别有哪几种?
TransactionDefinition 接口中定义了五个表示隔离级别的常量:

TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,
Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别。

TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取未提交的数据变更,
可能会导致脏读、幻读或不可重复读。

TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,
可以阻止脏读,但是幻读或不可重复读仍有可能发生。

TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,
除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。
所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
  • Spring 事务中哪几种事务传播行为?
支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;
如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;
如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;
如果当前没有事务,则抛出异常。(mandatory:强制性)不支持当前事务的情况:

不支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,
如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,
如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,
如果当前存在事务,则抛出异常。

其他情况:
TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;
如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
  • 前面说到@Transactional注解只能用在public 方法上,这是为什么?
Spring事务的实现都是依靠AOP,本质上也是依靠代理来实现。事务在spring中的实现其实就是生成bean对象的代理对象。
在bean进行创建出实例时, 如果是有事务注解的方法,就会被进行增强,最终形成代理类。
在spring中,有两种动态代理的方式,一种是jdk,它是将原始对象放入代理对象内部,通过调用内含的原始对象来实现原始的业务逻辑,
而另一种是cglib,它是通过生成原始对象的子类,子类复写父类的方法,从而实现对父类的增强。
jdk中,如果是private的方法,显然是无法访问的,
而在cglib中,也是同样。所以总结来说private方法不能被继承,
final方法不能被重写,static方法和继承不相干,所以它们3个的事务不起作用。
Spring选择让protected方法和package方法不支持事务,所以只有public方法支持事务
  • 同一个类中标有@Transactional 的方法A,调用另一个标有@Transactional的 方法B会开启几个事务?
一个事务
Spring事务管理用的是AOP,AOP底层用的是动态代理。
所以spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,
如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。
此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,
代理类在调用之前就会启动transaction。
如果是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,
所以就不会启动transaction,我们说只有一个事务。
  • 那么如何才能让上面两个方法开启两个事务呢?
1.把方法B抽离到另外一个XXService中去,在这个Service中注入XXService,使用XXService调用方法B;
2.通过在方法内部获得当前类代理对象的方式,通过代理对象调用方法B
上面说了:动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!所以我们就使用代理对象来调用,就会触发事务;
综上解决方案,那怎么获取代理对象呢? 这里提供两种方式:
   1.使用 ApplicationContext 上下文对象获取该对象;
   2.使用 AopContext.currentProxy() 获取代理对象,但是需要配置exposeProxy=true
   		TestService testService = (TestService)AopContext.currentProxy();
        testService.B();
   
 同时还需要在B方法将传播行为配置为  @Transactional(propagation = Propagation.REQUIRES_NEW)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值