spring事务面试题

你是如何理解Spring事务的传播机制的?底层是如何实现的?

spring事务面试题_第1张图片
一个线程在运行过程中,可能会连续调用好几个方法,在调用某一个方法时,可能就开启了一个Spring事务,那么在调用接下来的方法时,到底是共用同一个事务呢?还是新开一个事务呢?这就是传播机制,程序员可以根据不同的业务场景进行配置,比如:
9. REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
10. SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
11. MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
12. REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务。
13. NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务
14. NEVER:不使用事务,如果当前事务存在,则抛出异常
15. NESTED:如果当前事务存在,则在嵌套事务中执行,否则和REQUIRED的操作一样(开启一个事务)

在Spring中,一个Spring事务就是对应一个数据库连接,新开一个Spring事务其实就是新开一个数据库连接,比如执行某个方法时需要开启一个Spring事务,那么就会创建一个数据库连接,然后开始执行方法,如果方法中调用了其他方法,此时就会看这个其他方法怎么配置的:
16. 比如是REQUIRES_NEW,那么就会新开一个数据库连接,这个其中方法中的sql就会在这个新开的数据库连接中执行
17. 比如是REQUIRED,那么就不会新开,而是基于之前的数据库连接来执行方法中的sql

什么情况下spring事务会失效

  1. 方法内的自调用:Spring事务是基于AOP的,只要使用代理对象调用某个方法时,Spring事务才能生效,而在一个方法中调用使用this.xxx()调用方法时,this并不是代理对象,所以会导致事务失效。
    a. 解放办法1:把调用方法拆分到另外一个Bean中
    b. 解决办法2:自己注入自己
    c. 解决办法3:AopContext.currentProxy()+@EnableAspectJAutoProxy(exposeProxy = true)
  2. 方法是private的:Spring事务会基于CGLIB来进行AOP,而CGLIB会基于父子类来失效,子类是代理类,父类是被代理类,如果父类中的某个方法是private的,那么子类就没有办法重写它,也就没有办法额外增加Spring事务的逻辑。
  3. 方法是final的:原因和private是一样的,也是由于子类不能重写父类中的final的方法
  4. 单独的线程调用方法:当Mybatis或JdbcTemplate执行SQL时,会从ThreadLocal中去获取数据库连接对象,如果开启事务的线程和执行SQL的线程是同一个,那么就能拿到数据库连接对象,如果不是同一个线程,那就拿到不到数据库连接对象,这样,Mybatis或JdbcTemplate就会自己去新建一个数据库连接用来执行SQL,此数据库连接的autocommit为true,那么执行完SQL就会提交,后续再抛异常也就不能再回滚之前已经提交了的SQL了。
  5. 没加@Configuration注解:如果用SpringBoot基本没有这个问题,但是如果用的Spring,那么可能会有这个问题,这个问题的原因其实也是由于Mybatis或JdbcTemplate会从ThreadLocal中去获取数据库连接,但是ThreadLocal中存储的是一个MAP,MAP的key为DataSource对象,value为连接对象,而如果我们没有在AppConfig上添加@Configuration注解的话,会导致MAP中存的DataSource对象和Mybatis和JdbcTemplate中的DataSource对象不相等,从而也拿不到数据库连接,导致自己去创建数据库连接了。
  6. 异常被吃掉:如果Spring事务没有捕获到异常,那么也就不会回滚了,默认情况下Spring会捕获RuntimeException和Error。
  7. 类没有被Spring管理
  8. 数据库不支持事务

 Spring AOP是如何实现的?它和AspectJ有什么区别?

spring事务面试题_第2张图片
Spring AOP是利用的动态代理机制,如果一个Bean实现了接口,那么就会采用JDK动态代理来生成该接口的代理对象,如果一个Bean没有实现接口,那么就会采用CGLIB来生成当前类的一个代理对象。代理对象的作用就是代理原本的Bean对象,代理对象在执行某个方法时,会在该方法的基础上增加一些切面逻辑,使得我们可以利用AOP来实现一些诸如登录校验、权限控制、日志记录等统一功能。

Spring AOP和AspectJ之间并没有特别强的关系,AOP表示面向切面编程,这是一种思想,各个组织和个人都可以通过技术来实现这种思想,AspectJ就是其中之一,它会在编译期来对类进行增强,所以要用AspectJ,得用AspectJ开发的编译器来编译你的项目。而Spring AOP则是采用动态代理的方式来实现AOP,只不过觉得AspectJ中设计的那几个注解比较好,比如@Before、@After、@Around等,同时也不给程序员造成困扰,所以Spring AOP中会对这几个注解进行支持,虽然注解是相同的,但是底层的支持实现是完全不一样的。

你可能感兴趣的:(spring,java,mybatis)