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();
}
}