springboot事务

发布于:2021-07-19 20:40:48

目录


1、事务介绍?


2、springboot事务流程?


3、springboot中的事务的传播特性?


4、springboot中的事务的隔离性?mysql?的事务隔离级别:Repeatable Read?


5、readOnly属性 (默认false)?


6、其他属性?


7、在SpringBoot2.0中使用使用需要注意的地方。?


参考:



1、事务介绍?

1.1事务?


? ? ? ? ? ? ? 应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。?


1.2?事务的特征ACID?


? ? ? ? ? (1)原子性Atomicity:一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。?


? ? ? ? ? (2)一致性Consistency:事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。?


? ? ? ? ??(3)隔离性Isolation:一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。?


? ? ? ? ? (4)持久性Durability:持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。?


2、springboot事务流程?

1.1 当@Transactional注解的方法被类外部的代码调用时,Spring在运行时为方法所在类生成一个AOP代理对象。?代理对象根据@Transactional的属性,决定是否由事务拦*鱐ransactionInterceptor对此方法进行事务拦截。在进行事务拦截时,会先开启事务,然后执行业务代码,根据执行是否出现异常,通过抽象事务管理器AbstractPlatformTransactionManager来进行rollback或者commit。?


1.2? ? 在进行方法调用的时候,发现这个方法有事务注解,AOP首先会检测到,然后用代理类采用反射机*械饔谩?


? ? ? ? ? ? ? ? (1)首先调用了CglibAopProxy.intercept()方法。?


? ? ? ? ? ? ? ? (2)接下来调用ReflectiveMethodInvocation.proceed()方法,?


? ? ? ? ? ? ? ? (3)TransactionInterceptor.invoke()?


? ? ? ? ? ? ? ? (4)TransactionAspectSupport.invokeWithinTransaction()?


? ? ? ? ? ? ? ? (5)TransactionAspectSupport.createTransactionIfNecessary()?


? ? ? ? ? ? ? ? (6)?AbstractPlatformTransactionManager.getTransaction(),创建了一个新的事务。


1.3事务回滚时机:任何的RuntimeExcetipn、Error将触发回滚,任何的checkedException不触发回滚??


3、springboot中的事务的传播特性?

3.1 Propagation.REQUIRED(默认属性):如果当前没有事务?,则自己新建一个事务?,子方法是必须运行在这个事务中的?;?如果当前存在事务?,?则加入这个事务?,?成为一个整体。一般用于增删改。?


? ? ? ? ? ? ? ? ?A、使用条件:暂时未知?


? ? ? ? ? ? ? ? ?B、回滚策略:?


? ? ? ? ? ? ? ? ? ? ? ? ? ① 内/外只要有报错,他俩会一起回滚。?
? ? ? ? ? ? ? ? ? ? ? ? ? ② 只要内层方法报错抛出异常,即使外层有try-catch,该事务也会回滚。?


? ? ? ? ? ? ? ? 理解:1、外层事务先提交?


? ? ? ? ? ? ? ? ? ? ? ? ? ?2、事务1(REQUIRED),事务2(REQUIRED),事务3(REQUIRED);事务3调用事务1和事务2。那么事务1事务2事务3其实就是一个事务,只要有一个出现异常则都会回滚。?


3.2 Propagation.SUPPORTS:?如果当前有事务?,?则使用事务?,如果当前没有事务?,则不使用事务。适用于查询?


? ? ?? ? ?? ? ?A、使用条件:暂时未知?


? ? ?? ? ?? ? ?B、回滚策略:同REQUIRED?


? ? ? ? ? ? ? ? ? ? ? ? ?①?外层事务正常,内层报错,即使外层有无try-catc→ 内外层都回滚?
? ? ? ? ? ? ? ? ? ? ? ? ?②?外层事务异常,内层正错?→?内外层都回滚。?


? ? ? ? ? ? ? ? ? ? ? ? ?③ 外层无事务正常,内层报错→外层正常提交。?


3.3 Propagation.MANDATORY :?该传播属性强制必须存在一个事务,加入当前事务?,如果不存在,则抛出异常;?


? ? ?? ? ?? ? A、使用条件:必须是事务方法调用此方法?


? ? ?? ? ?? ? B、回滚策略:同REQUIRED?


3.4?Propagation.NEVER?:?以非事务方式执行,如果当前有事务存在?,则抛出IllegalTransactionStateException异常;?


? ? ?? ? ?? ? A、使用条件:外层无事务?


? ? ?? ? ?? ? B、回滚步骤:?


? ? ? ? ? ? ? ? ? ? ? ? ?①?外层事务正常,内层有无报错→内外层都回滚。?


? ? ? ? ? ? ? ? ? ? ? ? ?② 内外层无事务,都提交。?


3.5 Propagation.NOT_SUPPORTED :以非事务方式执行,如果当前有事务?,则把事务挂起?;?


? ? ?? ? ?? ? A、使用条件:未知?


? ? ?? ? ?? ? B、回滚步骤:?


? ? ? ? ? ? ? ? ? ? ? ? ?①?外层事务正常,内层报错→外层回滚,内层提交?


? ? ? ? ? ? ? ? ? ? ? ? ?② 外层事务正常,内层报错,且try-catch →内外层都提交?


3.6 Propagation.REQUIRES_NEW :?如果当前有事务?,则挂起事务?,并且自己创建一个新的事务给自己使用;?如果当前没有事务?,?则同required一样?。这种独立的内部事务还可以声明其自己的隔离级别、超时和仅读设置,并且不继承外部事务的特征。注意:创建的新的事务先提交?


? ? ?? ? ?? ? A、使用条件:暂时未知?


? ? ?? ? ?? ? B、回滚步骤:?


? ? ? ? ? ? ? ? ? ? ? ? ①?内层报错回滚,外层也回滚。外层try-catch内层的异常,外层不会回滚。?


? ? ? ? ? ? ? ? ? ? ? ? ②?外层报错回滚,不影响内层。?


3.7 Propagation.NESTED :?如果当前有事务,则开启子事务(嵌套事务),?嵌套事务是独立提交或者回滚的?。?


? ? ?? ? ?? ? A:使用条件,?


? ? ? ? ? ? ? ? ? ? ? ? ① JDK版本要在1.4以上,有java.sql.Savepoint。因为nested就是用savepoint来实现的。?


? ? ? ? ? ? ? ? ? ? ? ? ② 事务管理器的nestedTransactionAllowed属性为true。?


? ? ? ? ? ? ? ? ? ? ? ? ③ JPA、Hibernate不支持嵌套事务,jdbc3.0以上支持嵌套事务。mybatis测试支持嵌套事务?


? ? ?? ? ?? ? B、回滚步骤:?


? ? ? ? ? ? ? ? ? ? ? ? ① 外层异常,内外都会回滚?


? ? ? ? ? ? ? ? ? ? ? ? ② 内层异常,内外都会回滚。try-catch 子事务,内存回滚,外层不回滚?


? ? ?? ? ?? ? 理解:1、如何使同一个事务中的两个子事务,是不同事务?可以使事务互不影响? REQUIRES_NEW、NESTED??


? ? ? ? ? ? ? ? ? ? ? ? ?2、 当同一个类中 事务1(REQUIRED) 调用 事务2(NEVER),不会报错?但是事务2、1都不会执行?


? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?当事务1(REQUIRED)是在类A,事务2(NEVER)是在类B,事务1调用事务2是会报错,且事务1、2都会会回滚?


4、springboot中的事务的隔离性?mysql?的事务隔离级别:Repeatable Read?

Isolation.DEFAULT(-1):?默认值,表示使用底层数据库的默认隔离级别。大部分数据库为READ_COMMITTED?


Isolation.READ_UNCOMMITTED(1):??未提交读(READ_UNCOMMITTED)是最低的隔离级别,其含义是允许一个事物读取另一个事物没提交的数据。优点在于并发能力高,适合那些对数据一致性没有要求而追求高并发的场景,最大缺点是出


现脏读。?


Isolation.READ_COMMITTED(2):?读写提交(READ_COMMITTED),一个事务只能读取另外一个事务已提交的数据,不能读取未提交的数据。该级别克服了脏读,但不可重复读。?


Isolation.REPEATABLE_READ(4):可重复读(REPEATABLE_READ),目标是克服读写提交中出现的不可重复读的现象,但会出现幻读。(幻读:两次查到的数据不一样)?


Isolation.SERIALIZABLE(8):串行化(SERIALIZABLE),是数据库最高的隔离级别,它能够完全保证数据的一致性,但性能降低了。?


◆?脏读(dirty read):当一个事务读取另一个事务尚未提交的修改时,产生脏读。??
◆??不可重复读(non-repeatable read):同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。:??
◆??幻像读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。??


对于查询:?


隔离界别?

脏读?

不可重复读?

幻读?

Read_uncommitted读写未提交的?

√?

√?

√?

Read_committed?读写已提交的?

×?

√?

√?

Repeatable_read?可重复读?

×?

×?

√?

serializable?

×?

×?

×?


5、readOnly属性 (默认false)?

readOnly=true表明所注解的方法或类只是读取数据。 readOnly=false表明所注解的方法或类是增加,删除,修改数据。?


理解:当前事务中如果出现了增删改语句,那么抛出异常TransientDataAccessResourceException。?


6、其他属性?

① rollbackFor属性?


Spring框架的事务管理默认地只在发生非受检异常(RuntimeException和Error)时才进行事务回滚。也就是说,当事务方法抛出受检异常(Exception中除了RuntimeException及其子类以外的)时不会进行事务回滚。怎么解决??


? ? ? ? ? ? ? ? @Transactional(rollbackFor=Exception.class)就可以实现,当发生受检异常(checked exceptions)时,事务也进行回滚。?



②RollbackForClassName官方解释:派生自Throwable的类名数组。你必须引起回滚的异常类名称的可选数组。?


? ? ? ? ? ? ? ?这个就不用像上面的异常一样把所有的受检异常全部回滚,由你自己决定哪些需要回滚。?


③noRollbackFor官方解释:不能回滚的异常类数组?


④NoRollbackForClassName ,与上面县相反?


⑤?value/transactionManager:可选的限定词,指定要使用的事务管理器。?


7、在SpringBoot2.0中使用使用需要注意的地方。?

3.1?加@Transactional的方法不能是private和protected修饰,private会直接报编译错误,protected不会报错。但是事务不起作用。?


3.2 @Transactional可以放在Controller下面直接起作用。?


3.3?@Transactional引入包问题,她有两个包:import javax.transaction.Transactional; 和?import org.springframework.transaction.annotation.Transactional; 这两个都可以用,对比了一下他们两个的方法和属性,发现后面的比前面的强大。建议后后面的。?


3.4 @Transactional 可以注解在类上面也可以注解在方法上面。?


?以下为自己的理解----


同类中:@Transactional?用法没有其他参数?


1、一个非事务方法调用另一个事务方法方法,不生效;?


spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是@Transactional注解无效。?


可以让他生效,方法一:放在另一个类中去,方法二:获取代理对象然后,调用这个方法。?


2、一个事务方法掉调用另一个非事务方法,生效;?


出现异常,同时回滚,不管try-catch与否。?


3、一个事务方法调用另一个事务方法,生效;?


? ? ? ? ? ? ?回滚步骤:两个方法应该是同一个事务,同时回滚。?


4、同一个类中,事务方法使用普通方法调用注解了事务【NESTED或者REQUIRED_NEW】方法他不会有对应的效果。只会把它当成普通方法作为这个事务的一部分同时回滚。要想生效可以获取他的代理对象然后调用。?


5、使用场景:【不同类中或者同一类中使用代理对象 调用】?


①当事务1调用事务2时,我需要事务1的执行成功与否不影响事务2执行,但是事务2的成功与否影响事务1的执行??


? ? ? ? ? ? ? ? ? 把事务2的传播属性设置为REQUIRED_NEW,最先执行事务2。?


② 当事务1调用事务2时,内层事务异常,内层回滚,外层不回滚??


? ? ? ? ? ? ? ? ? 把事务2的传播属性设置为NESTED,且try-catch内层的调用。?


补充:获取代理对象的方法


@Service
@Slf4j
@EnableAspectJAutoProxy(exposeProxy = true)
public class QuizServiceImpl extends AbstractShop implements IQuizService {

@Resource
private QuizLogMapper quizLogMapper;

@Resource
private ShopManageService shopManageService;

@Override
@Transactional(rollbackFor = Exception.class)
public void testA(){

QuizPO po = new QuizPO();
po.setSubject("测试主题一");
quizMapper.insert(po);
System.out.println("看看数据库是否有测试主体一");

// 开启子事务
try{
IQuizService iQuizService = (IQuizService) AopContext.currentProxy();
iQuizService.testB();
}catch (Exception e){
e.printStackTrace();
}
}

@Override
@Transactional(propagation = Propagation.MANDATORY )
public void testB(){
QuizPO po = new QuizPO();
po.setSubject("测试主题二");
quizMapper.insert(po);
throw new IllegalArgumentException("我抛出了异常!看看数据库还有没有的数据!");
}
}

参考:

? ? ? ? ? ?1、官方?Data Access (spring.io)??页面内搜索1.4.7?Transaction Propagation?了解事务的传播?


? ? ? ? ? ?2、(2条消息) Spring 注解@Transactional readOnly=true_方逸涛的专栏-CSDN博客?


? ? ? ? ? ?3、?深入理解 Spring 之 SpringBoot 事务原理


? ? ? ? ? 4、spring,springboot之事务(事务传播机制详解、嵌套事务)_springboot事务传播机制?

相关推荐

最新更新

猜你喜欢