分享三道我在面试过程中遇到频率最高的三道spring面试题!
话不多说,直接上干货!
Spring中的事务是如何实现的
1. Spring事务底层是基于数据库事务和AOP机制的实现的
2.首先对于使用了@Transactiona注解的Bean, Spring会创建一个代理对象作为Bean
3.当调用代理对象的方法时,会先判断该方法上是否加了@Transactional注解
4.如果加了,那么则利用事务管理器(transactionManager)创建一个数据库连接
5.并且修改数据库连接的autocommit属性为false,禁止此连接的自动提交,这是实现Spring事务非常重要的一步
6.然后执行当前方法,方法中会执行sql
7.执行完当前方法后,如果没有出现异常就直接提交事务
8.如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
9. Spring事务的隔离级别对应的就是数据库的隔离级别
10. Spring事务的传播机制是Spring事务自己实现的,也是Spring事务 中最复杂的
11. Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务, 如果传播机制配置为需要新开一个事务, 那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql个数据库连接
什么时候@transaction注解会失效?
1.因为Spring事务是基于代理来实现的,所以某个加了@Transaction的方法只有是被代理对象调用时,那么这个注解才会生效,所以如果是被代理对象来调用这个方法,那么@Transaction是不会生效的。
代理基础
在Spring框架中,事务管理通过使用动态代理实现。这意味着当你在一个类的方法上加上 @Transactional 注解时,Spring运行时会创建这个类的一个代理(Proxy),并在这个代理类中包装原始类的事务逻辑。实际上,当你调用一个被 @Transactional 注解的方法时,你是在调用一个代理对象的方法,这个代理对象在调用真实对象的方法之前和之后,会分别处理事务的开始和结束。
自调用问题
当一个代理对象的方法内部调用同一对象的另一个 @Transactional 方法时,事务注解会失效。这是因为代理的事务管理逻辑只在从代理对象到目标对象的方法调用过程中起作用。如果是在目标对象内部的方法间调用(也称为自调用),则调用不会经过代理对象,因此不会执行代理中的事务处理逻辑。
具体例子
假设有一个服务类 BookService,其中包含两个方法:updateBookPrice 和 updateBookStatus,两者都被 @Transactional 注解:
@Service
public class BookService {
@Transactional
public void updateBookPrice(Long bookId, BigDecimal newPrice) {
// 更新书籍价格的逻辑
updateBookStatus(bookId, "UPDATED"); // 自调用
}
@Transactional
public void updateBookStatus(Long bookId, String status) {
// 更新书籍状态的逻辑
}
}
在上述代码中,当从外部调用 updateBookPrice 方法时,由于这个方法被 @Transactional 注解,Spring会通过代理来管理事务。然而,在 updateBookPrice 方法内部调用 updateBookStatus 方法时,由于是在同一个实例内部的直接方法调用,这个调用不会经过代理,因此 updateBookStatus 方法上的 @Transactional 注解不会有任何效果,事务管理逻辑不会被执行。
2.同时如果某个方法是private的,那么@Transaction也会失效,因为底层cglib是基于父子类来实现的,子类是不能重载父类的private方法的,所以无法很好的利用代理,也会导致@Transaction失效。
3.还有一个的话就是rollbackFor属性,如果你报的异常不是rollback所指定的异常的话其实它的注解也会失效。因为并没有进行回滚
spring中使用到的设计模式?
工厂设计模式:spring通过beanfactory、ApplicationContext创建bean对象
单例模式:spring中的bean默认都是单例的
代理模式:比较常见的就是spring AOP功能的实现
模版模式:例如jdbctemplate
策略模式:Spring的资源访问策略使用策略模式,允许从不同的数据源加载资源,通过Resource接口,Spring可以根据不同的URL前缀来选择不同的策略实现。
观察者模式:spring事件驱动模式就是观察者模式一个很好的例子。
定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的 对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener
责任链模式:例如spring通过拦截器链将advice进行分装,与代理模式配合完成aop功能。