程式狂想筆記

一個攻城師奮鬥史

0%

Spring 交易事務失效

最近接觸 Spring 專案搭配使用 Hibernate 後來想到應該是Spring-Tx
但是使用上常常處理事務跟我想要的結果不一樣
這個沒有研究清楚,常常事務那邊會一直卡住
最近剛好查到資料,這邊整理一下吧

主要原因

最近有時候發現交易沒有生效
最近翻到這篇文章
原來需要注意這個部分

這兩篇寫得很棒
簡單總結一下

上圖簡單說明,使用 Transactional 會用代理模式開啟 DB 事務
但為什麼第一層 Transactional 方法呼叫同個類別(Class)的方法會沒有新開事務呢
會看到代理(Proxy)類別呼叫第二層是呼叫到原本的(不是 Proxy)類別的 method
所以…當然就沒有代理

這時候在想要怎麼新開獨立事務
第一篇寫得很清楚

玩轉Spring —— 消失的事務 - 知乎 這篇文章就是講剛剛的問題,但沒有講要怎麼解決,最後我找到一篇有說要怎麼解決
一個@Transaction哪裡來這麼多坑? - 程序員DMZ - 博客園業務代碼層面這邊有程式碼例子,並且解決方法

第二個例子

1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class DmzService {
@Transactional
public void save(A a, B b) {
saveB(b);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveB(B b){
dao.saveB(a);
}
}

兩個@Transactional,saveB 不會新開事務
我覺得這個跟第一個原因很像
因為 AOP 代理 第一層做,但是this.saveB 會抓到原本類別 saveB method
之前學 Spring 有聽過一個口訣,@Transactional 會抓外面優先執行

這邊注意遺下優先抓外面,但邏輯是比較有沒有交易連線
REQUIRES_NEW 會抓建立新的連線機制

可以看一下交易事務:Spring事務傳播行為詳解 - 個人文章 - SegmentFault 思否

最近也有查到@Transactional class和 method,會優先抓 method 的@Transactional
沒使用 public method 也會失敗,原因是 AOP 的方法需要 public

要做事務處理建議使用 XXX.save()
這邊 XXX 是指 Spring 注入的對象
這跟下面解決方式一樣

Spring默認拋出了未檢查unchecked異常(繼承自 RuntimeException 的異常)或者 Error才回滾事務;其他異常不會觸發回滾事務,已經執行的SQL會提交掉。如果在事務中拋出其他類型的異常,但卻期望 Spring 能夠回滾事務,就需要指定 rollbackFor屬性。

這邊之後有時間在探討這個問題,這篇只先記錄事務處理

問題來了,這些要怎麼解決?

解決

一個@Transaction哪裡來這麼多坑? - 程序員DMZ - 博客園下免有兩個方法

  1. 自己注入自己
    所有 AOP 需要特別建立事務,需要用這個方法比較不會遇到問題
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class DmzService {
// 自己注入自己
@Autowired
DmzService dmzService;

@Transactional
public void save(A a, B b) {
dmzService.saveB(b);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveB(B b){
dao.saveB(a);
}
}
  1. 正規方法
1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class DmzService {

@Transactional
public void save(A a, B b) {
((DmzService) AopContext.currentProxy()).saveB(b);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveB(B b){
dao.saveB(a);
}
}

詳細看這兩篇,解決我在 Spring 交易事務的疑惑
沒這兩篇的話,我可能就無法還技術債

相關交易處理

這邊也說得很細
Spring 中的事務傳播 - 個人文章 - SegmentFault 思否

希望我有時間再整理這些差別

最近在想有什麼方法可以看到交易事務處理狀態
原本有找到用 Wireshark 抓封包看
看完這篇應該是不需要了 :)

Hibernate 有時起事務會失敗,外層加 @Transactional 就能解決
這邊就放起個小彩蛋連結(我就不整理了)

2021-08-02

有看到比較完整介紹交易文章。詳細瞭解 Spring Transaction 的 Propagation 備份圖