@Transactional 注解下,事务失效的多种场景
package com.example.api.demo.boke;
import com.example.api.demo.config.exceptions.MyException;
import org.springframework.transaction.annotation.Transactional;
/**
* @Transactional
* 注解下,事务失效的七种场景
*/
public class Transaction {
/**
* 1 异常被捕获后没有抛出
* 当异常被捕获后,并且没有再抛出,那么updateStudentA是不会回滚的。
*/
@Transactional
public void updateStudent() {
this.updateStudentA();
try {
int i = 1 / 0;
this.updateStudentB();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 2 抛出非运行时异常
* 异步虽然抛出了,但是抛出的是非RuntimeException类型的异常,依旧不会生效。
*/
@Transactional
public void updateStudent2() throws MyException{
this.updateStudentA();
try {
int i = 1 / 0;
this.updateStudentB();
} catch (Exception e) {
throw new MyException();
}
}
/**
* 3 方法内部直接调用
* 如果先调用updateStudent3(),那么updateStudent3()是不会回滚的,其原因就是@Transactional根本没生成代理,
*/
public void updateStudent3() throws MyException{
updateStudentG();
}
@Transactional
public void updateStudentG() throws MyException{
this.updateStudentA();
int i = 1 / 0;
}
/**
* 4 新开启一个线程
* 如下的方式updateStudentA()也不会回滚,因为spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,
* 新开启一个线程获取到的连接就不是同一个了。
*/
@Transactional
public void updateStudent4() throws MyException{
this.updateStudentA();
try {
Thread.sleep(1000); //休眠1秒,保证updateStudentA先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
int i = 1/0;
}).start();
}
/**
* 5 注解到private方法上
* idea直接会给出提示Methods annotated with ‘@Transactional’ must be overridable ,原理很简单,private修饰的方式,spring无法生成动态代理。
*/
@Transactional
private void updateStudent5() throws MyException {
this.updateStudentA();
int i = 1/0;
}
/**
* 6、 据库本身不支持: mysql数据库,必须设置数据库引擎为InnoDB。
* 7、 事务传播属性设置错误, 比如设置了:PROPAGATION_NOT_SUPPORIED(以非事务的方式执行,如果当前有事务则把当前事务挂起)
* 8、 事务方法被final、static修饰
* 9、 当前类没有被Spring管理
*/
private void updateStudentB() {
System.out.println();
}
private void updateStudentA() {
System.out.println();
}
}
学海无涯 代码作伴