成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

事務篇:Spring事務的坑,你都踩過嗎?

數據庫 其他數據庫
日常中最容易出現事務失效或者不能按照預期執行的情況,大致分為四類:自身調用、異常被吃、異常拋出類型不對以及事務的傳播機制不熟悉。

本篇,我們將要從本人以及同事在工作中踩過的關于事務的坑,以及踩坑之后自己在發現的使用 Spring 事務存在的坑展示給大家,讓大家也避免踩坑

一、來看看這些事務之坑

總得來說呢,經常遇到的其實是這四類:自身調用、異常被吃、異常拋出類型不對以及事務的傳播機制不熟悉

具體例子,我們來看看:

1.數據庫引擎不支持事務

感覺這種一般估計不太會出現。畢竟你要使用事務,肯定會在最開始就選擇支持事務的數據庫引擎咯

比如常用的 oracle 直接就是支持事務的,而 mysql 的 innodb 支持事務,myIsam 的話,是不支持事務的

在 mysql5.1 版本之前,默認引擎是 myIsam ,而之后的版本則默認就是innodb 了~

建議檢查項:mysql的數據庫引擎。

執行命令:

show variables like '%storage_engine%';

我們看到,我本地的 5.7 版本 的 mysql 數據庫的數據庫引擎默認就是 innodb

2.方法不是 public 的

其實經過本人的測試,除了 private 方法本身就不能編譯通過以外,public、protected 以及 default 三個修飾符都是支持事務的

有興趣,你也可以測試一下!

3.自身調用問題

比如在同一個類中的兩個方法 methodA 和 methodB 。methodA 沒有設置事務,methodB 設置了事務,methodA 調用 methodB 時,事務便會失效

1) 同一個類中的方法調用

/**
* 自調用測試:事務失效,表中新增了兩條數據:id為10和11的數據
*/
@Override
public void testInvokeBInOneClass(){
User user = User.builder().id(10).name("王二").age(22).build();
userDao.addUser(user);
testB();
}

@Transactional
public void testB(){
User user = User.builder().id(11).name("張三").age(22).build();
userDao.addUser(user);
int i = 1/0;
}

我們預測一下:

若事務失效,數據庫中將會成功增加兩條數據:王二和張三

若事務生效,則表中將不會增加任何數據

執行該方法后,我們會發現,數據庫的 t_user2 表中的記錄為:

沒錯,結果,事務失效了

2)不同類中的方法調用

我們把 testB () 方法放到另一個類 TransactionBImpl 中

此時,調用 TransactionBImpl 類中的 testB () 方法;

/**
* 自調用測試:事務生效,表中新增了一條數據:id為10的數據
*/
@Override
public void testInvokeBInTwoClass(){
User user = User.builder().id(10).name("王二").age(22).build();
userDao.addUser(user);
transactionB.testB();
}

發現數據庫中的數據為:

說明事務生效了,為什么呢?

因為外層 testInvokeBInTwoClass() 方法本身是沒有事務(沒有加事務注解)的,它調用了另一個類中 加了事務注解的 testB() 方法,不要忘記 @Transactional 注解的默認傳播機制,是PROPAGATION_REQUIRED - 若不存在事務,就要自己創建一個新事務

也就是說,最終的效果就是,testB() 方法內部在一個事務內,testInvokeBInTwoClass()方法中,并沒有事務(不會因為異常而觸發回滾操作)

那么,最終的結果,也就輕易理解咯~

如果你聽過獨立事務的話,就能想到它的實現機制了吧!

Tips

有些業務需要,要求 methodA 調用 methodB 時,并不會因為 methodB 的執行失敗,而影響了調用之前的操作。如在在表中調用之前登記了一條狀態日志,此時并不想要因為調用失敗,而回滾了這條記錄,就可以這樣操作啦~

小結

事務在發生自調用時,若調用方沒有加 @Transactional 注解,事務便會失效

若要使事務生效,則可以考慮將該被調用的方法放在另一個類中即可

4.不支持事務

這種情況比較容易理解,只是會在編碼過程中容易被忽略掉,所以在這里也提一下

當 methodA 調用另一個類中的 methodB ,若 methodB 設置了事務的傳播機制為Propagation.NOT_SUPPORTED

那么,即使 methodA 開啟了事務,也不一定會按照自己的預期來發展的,來看看下面這個例子:

UserServiceImpl 類

 @Override
public void testNotSupported() {
User user = User.builder().id(10).name("王二").age(22).build();
userDao.addUser(user);
transactionB.testNotSupported();
}

TransactionBImpl 類

@Transactional
(propagation = Propagation.NOT_SUPPORTED)
@Override
public void testNotSupported(){
User user = User.builder().id(11).name("張三").age(22).build();
userDao.addUser(user);
int i = 1/0;
}

即,UserServiceImpl 類中的 testNotSupported()方法調用了 TransactionBImpl 類 中的 testNotSupported()方法

我們來分析一下,按照調用方是否開啟事務,可以分為以下兩種情況 :

1)若調用方 testNotSupported()方法不加 @Transactional 注解,則表中數據為:

顯而易見,說明兩個方法統一都沒有事務

若加上,則只插入了一條數據

說明外部方法還是存在事務的,只要出現異常就會回滾。而被調用方 transactionB.testNotSupported() 的方法內部不支持事務,于是該方法出錯之后也不會出現事務回滾,因此出錯之前的插表操作就沒有回滾

5.異常被catch住了,沒有拋出來

由于事務默認回滾的是:RuntimeException 和 Error 兩種情況,所以以下兩種情況都會失效

1)異常被吃了,事務失效

/**
* 7、異常被吃了:try掉異常(未拋出),事務失效
*/
@Transactional
@Override
public void testException(){
try {
User user = User.builder().id(10).name("王二").age(22).build();
userDao.addUser(user);
int i = 1/0;
}catch (Exception e) {
System.out.println("執行失敗:"+e.getMessage());
// throw new RuntimeException("執行失敗,拋出異常:"+e.getMessage());
}
}

也就是說,異常并沒有被拋出來,而是通過 catch 住,然后做了一些其他的邏輯處理,這種事務是不會生效的

再來看看第二種情況

2)拋出Exception異常,事務失效

@Transactional
@Override
public void testException() throws Exception {
try {
User user = User.builder().id(10).name("王二").age(22).build();
userDao.addUser(user);
int i = 1/0;
}catch (Exception e) {
System.out.println("執行失敗:"+e.getMessage());
throw new Exception("拋出了Exception異常:"+e.getMessage());
// throw new RuntimeException("執行失敗,拋出異常:"+e.getMessage());
}
}

回想一下我們的大前提:Spring事務默認回滾的是:RuntimeException和Error兩種情況。現在拋出了 Excption ,就不會觸發事務的回滾,所以這樣事務也是不生效的

要怎樣才能讓這樣的事務生效呢?

改成拋出 RuntimeException 事務就生效啦~ 你完全可以現在就試試

對了,如果你想觸發其他異常的回滾,包括你自己定義的異常或者 Exception 異常的話,也不是沒有辦法。只需要在方法的注解上配置一下 rollbackFor 屬性即可,如:@Transactional(rollbackFor = Exception.class)。

留一個思考題給你:若配置了其他異常,那原本的規則是否被覆蓋掉?

小結

只要抓住一點:事務默認在:RuntimeException 和 Error 兩種情況下執行回滾操作

因此,

1)異常被捕獲掉,沒有拋出來,就不會生效

2)拋出的 RuntimeException 異常或者未遇到 Error ,事務默認也不會生效的

那么,怎么處理才能讓事務生效,想必已經很明顯了吧?

6.未啟用spring事務管理功能

@EnableTransactionManagement 注解用來啟用spring事務自動管理事務的功能,只有有這個注解,這個注解千萬不要忘記寫了

但是當引入了;

spring-boot-starter-jdbc

就可以不用我們自己寫,為什么呢?我們來看看;

@EnableTransactionManagement 這個注解開啟事務,其實和我們自己使用@EnableTransactionManagement是一樣的 因此,只要我們在 SpringBoot 中引入了 spring-boot-starter-jdbc 這個依賴以后,我們就只需要使用 @Transactional 就可以了。

二、總而言之

好了,本篇文章,接著上一篇的事務基礎,為大家演示了幾個開發過程中容易出現的事務失效,或者事務不能按照自己的預期來執行的幾種場景。

總結一下,日常中最容易出現事務失效或者不能按照預期執行的情況,大致分為四類:自身調用、異常被吃、異常拋出類型不對以及事務的傳播機制不熟悉。

那么我們需要如何去避免踩坑,正確高效地使用事務呢?

很簡單,只需要關注單個方法時事務的回滾機制,以及涉及到兩個以及兩個以上方法的調用時事務的傳播機制以及Spring事務的原理。

  • 單個方法的調用,事務只會在執行過程中出現 RuntimeException 和 Error 以及事務超時時進行事務的回滾;
  • 多個方法:當在同一個類中進行方法調用時,若要事務不失效,則需要在調用方的方法都加上事務注解,同時需要關注事務的傳播機制以及各層方法的事務回滾情況;

不在同一類中時,則需要根據特定的業務場景,選擇不同的傳播機制。

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2025-02-10 00:27:54

2024-04-01 08:05:27

Go開發Java

2023-03-13 13:36:00

Go擴容切片

2019-09-25 15:30:15

2025-05-27 08:45:00

2019-10-30 14:44:41

Prometheus開源監控系統

2018-09-11 09:14:52

面試公司缺點

2025-04-29 10:17:42

2017-07-17 15:46:20

Oracle并行機制

2023-08-29 10:51:44

2023-09-08 08:52:12

Spring注解事務

2022-07-06 11:47:27

JAVAfor循環

2025-04-14 09:31:03

2019-12-12 14:32:26

SQL語句數據庫

2018-01-10 13:40:03

數據庫MySQL表設計

2025-02-06 07:45:44

2025-06-03 06:30:05

2018-08-01 14:45:16

PHP編程語言

2025-04-03 12:30:00

C 語言隱式類型轉換代碼

2025-04-15 02:00:00

API版本項目
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品一区二区三区在线播放 | 日韩视频在线观看中文字幕 | 欧美日韩一区不卡 | 三级视频在线观看电影 | 国产精品美女一区二区 | 成人性视频在线播放 | 国产激情一区二区三区 | 美女天天干天天操 | 久草在线| 亚洲日本国产 | 久草网站 | 国产一区二区三区视频免费观看 | 网站一区二区三区 | 在线成人免费视频 | 中文字幕乱码一区二区三区 | 夜夜操天天操 | 成人av网站在线观看 | 国产精品久久久久久亚洲调教 | 欧美一级在线 | 手机日韩 | 国产精品a级 | 日韩一级黄色毛片 | 91毛片在线观看 | 国产精品视频久久 | 岛国av免费在线观看 | 国产精品二区三区在线观看 | 亚洲精品高清视频在线观看 | av天天看| 天天搞天天搞 | 国产精品一区二区三区久久久 | 午夜免费视频 | 国产精品99久久久久久宅男 | 久久国产区| 在线播放国产一区二区三区 | 日韩av中文| 天堂亚洲 | 电影91久久久 | 成人网视频 | 超碰日本 | 午夜精品在线观看 | 亚洲综合热 |