Spring全家桶面试题(一)之Spring Framework(八)

六、Spring事务

56. 事务四大特性

⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚, 因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

57. Spring支持的事务管理类型,Spring 事务实现方式有哪些?

1. Spring支持两种类型的事务管理

编程式事务管理:这意味你通过编程的方式管理事务(可以手动控制事务的提交),给你带来极大的灵活性,但是难维护。
在这里插入图片描述

声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务(自动提交)

2. 实现声明式事务的三种方式

  1. 基于接口
  • a. 基于 TransactionInterceptor 的声明式事务: Spring 声明式事务的基础,通常也不建议使用这种方式,但是与aop
    一样,了解这种方式对理解 Spring 声明式事务有很大作用。
  • b. 基于 TransactionProxyFactoryBean 的声明式事务: 第一种方式的改进版本,简化的配置文件的书写,这是
    Spring 早期推荐的声明式事务管理方式,但是在 Spring 2.0 中已经不推荐了。
  1. 基于< tx> 和< aop>命名空间的声明式事务管理: 目前推荐的方式,其最大特点是与 Spring AOP 结合紧密,可以充分利用切点表达式的强大支持,使得管理事务更加灵活。
<!-- 配置事务管理器 -->
<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>

在这里插入图片描述
3. 基于 @Transactional 的全注解方式: 将声明式事务管理简化到了极致。开发人员只需在配置文件中加上一行启用相关后处理 Bean 的配置,然后在需要实施事务管理的方法或者类上使用 @Transactional 指定事务规则即可实现事务管理,而且功能也不必其他方式逊色。

<!-- 配置事务管理器 -->
<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>
 
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager" />

在这里插入图片描述

58. 说一下Spring的事务传播行为

事务的传播特性指的是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行?

 @Transactional
 public void trans(){
	 sub();
	 log(); // 记录流水 数据库操作
	 query();
 } 
 
@Transactional(SUPPORTS) 9 public info query(){
 ....
 }

 @Transactional REQUIRES_NEW
 public void log(){
 // todo: 记录日志
}
事务传播行为类型外部不存在事务外部存在事务使用方式
REQUIRED(默认)开启新的事务融合到外部事务中@Transactional(propagation = Propagation.REQUIRED)适用增删改查
SUPPORTS不开启新的事务融合到外部事务中@Transactional(propagation = Propagation.SUPPORTS)适用查询
REQUIRES_NEW开启新的事务不用外部事务,创建新的事务@Transactional(propagation = Propagation.REQUIRES_NEW)适用内部事务和外部事务不存在业务关联情况,如日志
NOT_SUPPORTED不开启新的事务不用外部事务@Transactional(propagation = Propagation.NOT_SUPPORTED) 不常用
NEVER不开启新的事务抛出异常@Transactional(propagation = Propagation.NEVER )不常用
MANDATORY抛出异常融合到外部事务中@Transactional(propagation = Propagation.MANDATORY)不常用
NESTED开启新的事务融合到外部事务中,SavePoint机制,外层影响内层, 内层不会影响外层@Transactional(propagation ==Propagation.NESTED)不常用

59.说一下 spring 的事务隔离?

用来解决并发事务所产生一些问题:
1.脏读
2.不可重复读
3.幻读

概念: 通过设置隔离级别可解决在并发过程中产生的那些问题:
1、 脏读
一个事务,读取了另一个事务中没有提交的数据,会在本事务中产生的数据不一致的问题
解决方式:@Transactional(isolation = Isolation.READ_COMMITTED)
读已提交:READ COMMITTED,要求Transaction01只能读取Transaction02已提交的修改。

2、不可重复读
一个事务中,多次读取相同的数据,但是读取的结果不一样,会在本事务中产生数据不一致的问题。
解决方式:@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读:REPEATABLE READ,确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。(行锁)

3、 幻读
一个事务中,多次对数据进行整表数据读取(统计),但是结果不一样, 会在本事务中产生数据不一致的问题。
解决方式:@Transactional(isolation = Isolation.SERIALIZABLE)
串行化:SERIALIZABLE,确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。(表锁)

很多人容易搞混不可重复读和幻读,确实这两者有些相似:
对于前者, 只需要锁行;对于后者, 需要锁表

MYSQL:REPEATABLE‐READ
ORACLE: READ_COMMITTED

60. Spring事务实现基本原理

1. 使用

@EnableTransactionManagement 打开@Transacational注解

2. 原理

1.解析切面 ——> bean创建前第一个bean的后置处理器进行解析advisor(advisor不是我们自己配的,而是有Spring声明事务自己提供给我们的,pointcut(满足有@Transacational注解) , advice环绕通知)
(这个advisor 是通过@EnableTransactionManagement注册了一个配置类,该配置类就配置了adivsor)

2.创建动态代理——> bean的初始化后调用bean的后置处理器进行创建动态代理(有接口使用jdk,没接口使用cglib), 创建动态代理之前会先根据advisor中pointCut 匹配@Transacational( 方法里面是不是有、类上面是不是有、接口或父类上面是不是有 ) , 匹配到就创建动态代理。

3.调用: 动态代理

try{
	4.创建一个数据库连接Connection, 并且修改数据库连接的autoCommit属性为false,禁止此连接的自动提交,这是
	实现Spring事务非常重要的一步
	5.然后执行目标方法方法,方法中会执行数据库操作sql 
}
catch{
   6.如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
}
7.执行完当前方法后,如果没有出现异常就直接提交事务

61. Spring事务传播行为实现原理

Spring的事务信息是存在ThreadLocal中的, 所以一个线程永远只能有一个事务

融入:当传播行为是融入外部事务则拿到ThreadLocal中的Connection、共享一个数据库连接共同提交、回滚;
创建新事务:当传播行为是创建新事务,会将嵌套新事务存入ThreadLocal、再将外部事务暂存起来; 当嵌套事务提交、回滚后,会将暂存的事务信息恢复到ThreadLocal中

融入

try{
	 1.外部.创建一个数据库连接Connection存入ThreadLocal, 并且修改数据库连接的autoCommit属性为false ,返回事务状态信息(TransactionInfo.newTransaction=true)
   2.外部.然后执行目标方法方法(调用了内部事务方法)方法中会执行数据库操作sql
	   3.内嵌:判断ThreadLocal是否已经有Connection,有的话就说明是一个内嵌事务, 判断当前事务的传播行为
		 融入:不会创建Connection,返回事务状态信息(TransactionInfo.newTransaction=false) 
		 4.内嵌:然后执行目标方法,方法中会执行数据库操作sql
}catch{
 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
}
	5.内嵌:判断newTransaction==false 就不提交事务
6.外部: 判断newTransaction==false 拿到ThreadLocal中的Connection进行提交

创建新事务

try{
	 1.外部.创建一个数据库连接Connection存入ThreadLocal, 并且修改数据库连接的autoCommit属性为false ,返回事务状态信息(Transactio
nInfo.newTransaction=true)
   2.外部.然后执行目标方法方法(调用了内部事务方法)方法中会执行数据库操作sql
	   3.内嵌:判断ThreadLocal是否已经有Connection,有的话就说明是一个内嵌事务, 判断当前事务的传播行为
		 创建新事务:会把外层事务相关的事务信息(Connection、隔离级别、是否只读....暂存,同时会把ThreadLocal存储的外层事务信息都
置空)
		 创建Connection放入ThreadLocal,返回事务状态信息(TransactionInfo.newTransaction=ture,TransactionInfo.外部事务的暂存信息)
		 4.内嵌:然后执行目标方法,方法中会执行数据库操作sql
}catch{
 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
}
	5.内嵌:判断newTransaction==true 就提交事务,判断是否暂存事务,把暂存的事务信息回归到ThreadLocal6.外部: 判断newTransaction==true 拿到ThreadLocal中的Connection进行提交

62. Spring多线程事务,能否保证事务的一致性(同时提交、同时回滚)?

1.Spring的事务信息是存在ThreadLocal中的Connection, 所以一个线程永远只能有一个事务,多个线程无法共享一个Connection
2. 所以Spring 的多线程事务是无法实现事务原子性和一致性的
3. 可以通过编程式事务,或者通过分布式事务的思路:二阶段提交方式

63.Spring事务的失效原因?

失效原因:

  1. 方法是private 也会失效,解决:改成public
  2. 目标类没有配置为Bean也会失效 解决:配置为Bean
  3. 自己捕获了异常 ,解决:不要捕获处理
  4. 使用cglib动态代理,但是@Transactional声明在接口上面

内部调用导致事务传播失效
解决方式:必须走代理, 重新拿到代理对象再次执行方法才能进行增强
1、. 在本类中自动注入当前的bean
2、 设置暴露当前代理对象到本地线程 @EnableAspectJAutoProxy(exposeProxy = true), 可以通过AopContext.currentProxy() 拿到当前正在调用的动态代理对象

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值