本地事务
回顾一下基础知识:
本地事务特性:
原子性(Atomicity)、一致性(Consistency)、隔离性或独立性(lsoklation)和持久性(Durabilily)
简称ACID
事务隔离级别: ---》isolation
1.READ UNCOMMITTED(读未提交)
该隔离级别的事务会读到其他未提交事务的数据,此现象又称为脏读
2.READ COMMITTED(读提交)
一个事物可以读取另一个事物已提交的事务,多次读取会造成不一样的结果,此现象称为不可重复读问题,Oracle和SQL server的默认隔离级别
3.REPEATABLE(可重复读)
该隔离级别是mysql默认的隔离级别,在同一个事物里,select的结果是事物开始时时间点的状态,因此,同样的select操作读到的结果是一致的,但是会有幻读现象
4.SERIALIZABLE(序列化)
在该隔离级别下事务都是串行顺序执行的,mysql数据库的InnoDB引擎会给读操作模式加一把读共享锁,从而避免了脏读,不可重复读和幻读
以上4种隔离级别的并发能力逐渐变弱
在Spring中注解实现@Transactional(isolation = Isolation.READ_UNCOMMITTED )
事务的传播行为---》propagation
1.PROPAGATION_REQUIRES: 如果当前没有事务,就创建一个新事物,如果当前存在事务,就加入事务,该设置是最常用的设置
2.PROPAGATION_SUPPORTS: 支持当前事务。如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行
3.PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果不存在事务,就抛出异常
4.PROPAGATION_REQUIRES_NEW: 创建新事务,无论当前存不存在事务,都创建新事务
5.RPOPAGATION_NOT_SUPPORTED: 以非事务方式执行操作,如果当前存在事务,就把事务挂起
6.PROPAGATION_NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常
7.PROPAGATION_NESTED: 如果当前存在事务,则在嵌套事物内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似操作
在Spring中注解实现@Transactional(propagation = propagation.xxxxxx )
Springboot踩坑:
同一个对象内事务方法互调默认无效
@Service
public class AffairServiceImpl {
@Transactional()
public void a(){
b(); //a事务
c(); //新事务
int i=10/0;
}
@Transactional(propagation = Propagation.REQUIRED)
public void b(){
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void c(){
}
}
如果这3个事务在一个service里面,那么b,c做的任何设置都会失效,都和a共用一个事物
事务是使用代理对象来控制的,原因是b,c绕过了代理对象
解决方案一(萌新):
要想使他们有用,必须让它们不在同一个service里面
@Service
public class AffairServiceImpl {
@Transactional()
public void a(){
bService.b(); //a事务
cService.c(); //新事务
int i=10/0;
}
如果我必须在本类方法中互调呢?
解决方案二:
1.引入spring-boot-starter-aop 引入了aspectj
2.@EnableAspectJAutoProxy:开启aspectj动态代理功能,以后所有的动态代理都是aspectj创建的(即使没有接口也可以创建动态代理),因为默认的是基于jdk的动态代理,jdk的动态代理必须要有接口
面试题:JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
- JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
- 如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
3.本类用代理对象互调
@Service
public class AffairServiceImpl {
@Transactional()
public void a(){
//AopContext.currentProxy(); 获取当前上下文的代理对象
AffairServiceImpl affairService = (AffairServiceImpl) AopContext.currentProxy();
affairService.b(); //a事务
affairService.c(); //新事务
int i=10/0;
}
@Transactional(propagation = Propagation.REQUIRED)
public void b(){
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void c(){
}
}