成人免费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語句數據庫

2025-06-03 06:30:05

2025-02-06 07:45:44

2018-01-10 13:40:03

數據庫MySQL表設計

2018-08-01 14:45:16

PHP編程語言

2022-10-11 11:38:23

Spring

2020-11-24 11:30:51

SpringJava代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 我爱操 | 久久久久久久久久一区 | 亚洲精品久久久一区二区三区 | 在线亚洲一区二区 | 亚洲欧美日韩成人在线 | 91在线免费视频 | 欧美精品在线一区 | 欧美综合国产精品久久丁香 | 国产日韩精品在线 | 免费播放一级片 | 亚洲午夜精品视频 | 亚洲免费人成在线视频观看 | 天天夜天天操 | 人妖一区 | 日韩欧美国产精品一区二区三区 | 羞羞的视频在线看 | 人人做人人澡人人爽欧美 | 日本午夜视频 | 综合二区| 中文字幕乱码一区二区三区 | av一二三区| 欧美国产视频 | 麻豆a级片 | 精品少妇一区二区三区在线播放 | 夜夜久久| 国产专区在线 | 国产片网站| 天堂久| 激情一区二区三区 | 成人天堂| 国产乱码精品1区2区3区 | 亚洲综合国产 | 精品欧美一区二区三区 | 啪啪毛片 | 日韩中文视频 | 久久精品av | 日本成人一区二区 | 日韩在线观看一区 | 黄色精品| 亚洲国产视频一区二区 | 五月激情婷婷六月 |