【面试题 - spring】二

这里写目录标题

  • 1. Spring事务的实现方式和实现原理
    • 1.1 spring支持编程式事务管理和声明式事务管理两种方式。
    • 1.2 事务的传播性
    • 1.3 事务超时( @Transactional(timeout=30) //默认是30秒)
      • 1.3.1 事务超时不生效
      • 1.3.2 demo
    • 1.4 spring事务回滚规则
    • 1.5 @Transactional注解

1. Spring事务的实现方式和实现原理

1.1 spring支持编程式事务管理和声明式事务管理两种方式。

  1. 编程式事务管理使用TransactionTemplate。
  2. 声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置内部文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,声明式事务管理使业务代码不受污染,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

1.2 事务的传播性

methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。
【面试题 - spring】二_第1张图片
详细介绍:https://blog.csdn.net/weixin_39625809/article/details/80707695
PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:
使用 PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。
使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务

1.3 事务超时( @Transactional(timeout=30) //默认是30秒)

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
@Transactional(timeout=30) //默认是30秒

1.3.1 事务超时不生效

transaction timeout,设置超时时间,每执行一次sql就check一次时间。注意,这里是每执行一次sql就check一次时间,代码中,执行插入sql时,check时间没超时,等再执行http请求时,这个不是sql,所以不会check过期时间,加上请求假死,所以,程序就hold在那,事务也不超时回滚。
Spring事务超时 = 事务开始时到最后一个Statement创建时时间 + 最后一个Statement的执行时超时时间(即其queryTimeout)。
所以,“总时长”是从方法开始,到执行完 jdbcTemplate.execute()方法截至。而不是到方法最后!!!!!!

1.3.2 demo

假设事务超时时间设置为2秒;假设sql执行时间为1秒;
如下调用是事务不超时的:

public void testTimeout() throws InterruptedException {  
    System.out.println(System.currentTimeMillis());  
    JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);  
    jdbcTemplate.execute(" update test set hobby = hobby || '1'");  
    System.out.println(System.currentTimeMillis());  
    Thread.sleep(3000L);  
}  

而如下事务是超时的:

public void testTimeout() throws InterruptedException {  
    Thread.sleep(3000L);  
    System.out.println(System.currentTimeMillis());  
    JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);  
    jdbcTemplate.execute(" update test set hobby = hobby || '1'");  
    System.out.println(System.currentTimeMillis());  
}  

1.4 spring事务回滚规则

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring只有在抛出的异常为运行时unchecked异常(RuntimeException的子类/Error的实现类)时才回滚该事务,而抛出checked异常(IOException)则不会导致事务回滚。可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务
将派生于Error或者RuntimeException的异常称为unchecked异常,所有其他的异常成为checked异常。

1.5 @Transactional注解

【面试题 - spring】二_第2张图片
@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

你可能感兴趣的:(spring,面试题2022,spring,java,面试)