国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

事務(wù)篇:Spring事務(wù)的坑,你都踩過(guò)嗎?

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù)
日常中最容易出現(xiàn)事務(wù)失效或者不能按照預(yù)期執(zhí)行的情況,大致分為四類(lèi):自身調(diào)用、異常被吃、異常拋出類(lèi)型不對(duì)以及事務(wù)的傳播機(jī)制不熟悉。

本篇,我們將要從本人以及同事在工作中踩過(guò)的關(guān)于事務(wù)的坑,以及踩坑之后自己在發(fā)現(xiàn)的使用 Spring 事務(wù)存在的坑展示給大家,讓大家也避免踩坑

一、來(lái)看看這些事務(wù)之坑

總得來(lái)說(shuō)呢,經(jīng)常遇到的其實(shí)是這四類(lèi):自身調(diào)用、異常被吃、異常拋出類(lèi)型不對(duì)以及事務(wù)的傳播機(jī)制不熟悉

具體例子,我們來(lái)看看:

1.數(shù)據(jù)庫(kù)引擎不支持事務(wù)

感覺(jué)這種一般估計(jì)不太會(huì)出現(xiàn)。畢竟你要使用事務(wù),肯定會(huì)在最開(kāi)始就選擇支持事務(wù)的數(shù)據(jù)庫(kù)引擎咯

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

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

建議檢查項(xiàng):mysql的數(shù)據(jù)庫(kù)引擎。

執(zhí)行命令:

show variables like '%storage_engine%';

我們看到,我本地的 5.7 版本 的 mysql 數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)引擎默認(rèn)就是 innodb

2.方法不是 public 的

其實(shí)經(jīng)過(guò)本人的測(cè)試,除了 private 方法本身就不能編譯通過(guò)以外,public、protected 以及 default 三個(gè)修飾符都是支持事務(wù)的

有興趣,你也可以測(cè)試一下!

3.自身調(diào)用問(wèn)題

比如在同一個(gè)類(lèi)中的兩個(gè)方法 methodA 和 methodB 。methodA 沒(méi)有設(shè)置事務(wù),methodB 設(shè)置了事務(wù),methodA 調(diào)用 methodB 時(shí),事務(wù)便會(huì)失效

1) 同一個(gè)類(lèi)中的方法調(diào)用

/**
* 自調(diào)用測(cè)試:事務(wù)失效,表中新增了兩條數(shù)據(jù):id為10和11的數(shù)據(jù)
*/
@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;
}

我們預(yù)測(cè)一下:

若事務(wù)失效,數(shù)據(jù)庫(kù)中將會(huì)成功增加兩條數(shù)據(jù):王二和張三

若事務(wù)生效,則表中將不會(huì)增加任何數(shù)據(jù)

執(zhí)行該方法后,我們會(huì)發(fā)現(xiàn),數(shù)據(jù)庫(kù)的 t_user2 表中的記錄為:

沒(méi)錯(cuò),結(jié)果,事務(wù)失效了

2)不同類(lèi)中的方法調(diào)用

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

此時(shí),調(diào)用 TransactionBImpl 類(lèi)中的 testB () 方法;

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

發(fā)現(xiàn)數(shù)據(jù)庫(kù)中的數(shù)據(jù)為:

說(shuō)明事務(wù)生效了,為什么呢?

因?yàn)橥鈱?testInvokeBInTwoClass() 方法本身是沒(méi)有事務(wù)(沒(méi)有加事務(wù)注解)的,它調(diào)用了另一個(gè)類(lèi)中 加了事務(wù)注解的 testB() 方法,不要忘記 @Transactional 注解的默認(rèn)傳播機(jī)制,是PROPAGATION_REQUIRED - 若不存在事務(wù),就要自己創(chuàng)建一個(gè)新事務(wù)

也就是說(shuō),最終的效果就是,testB() 方法內(nèi)部在一個(gè)事務(wù)內(nèi),testInvokeBInTwoClass()方法中,并沒(méi)有事務(wù)(不會(huì)因?yàn)楫惓6|發(fā)回滾操作)

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

如果你聽(tīng)過(guò)獨(dú)立事務(wù)的話,就能想到它的實(shí)現(xiàn)機(jī)制了吧!

Tips

有些業(yè)務(wù)需要,要求 methodA 調(diào)用 methodB 時(shí),并不會(huì)因?yàn)?methodB 的執(zhí)行失敗,而影響了調(diào)用之前的操作。如在在表中調(diào)用之前登記了一條狀態(tài)日志,此時(shí)并不想要因?yàn)檎{(diào)用失敗,而回滾了這條記錄,就可以這樣操作啦~

小結(jié)

事務(wù)在發(fā)生自調(diào)用時(shí),若調(diào)用方?jīng)]有加 @Transactional 注解,事務(wù)便會(huì)失效

若要使事務(wù)生效,則可以考慮將該被調(diào)用的方法放在另一個(gè)類(lèi)中即可

4.不支持事務(wù)

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

當(dāng) methodA 調(diào)用另一個(gè)類(lèi)中的 methodB ,若 methodB 設(shè)置了事務(wù)的傳播機(jī)制為Propagation.NOT_SUPPORTED

那么,即使 methodA 開(kāi)啟了事務(wù),也不一定會(huì)按照自己的預(yù)期來(lái)發(fā)展的,來(lái)看看下面這個(gè)例子:

UserServiceImpl 類(lèi)

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

TransactionBImpl 類(lèi)

@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 類(lèi)中的 testNotSupported()方法調(diào)用了 TransactionBImpl 類(lèi) 中的 testNotSupported()方法

我們來(lái)分析一下,按照調(diào)用方是否開(kāi)啟事務(wù),可以分為以下兩種情況 :

1)若調(diào)用方 testNotSupported()方法不加 @Transactional 注解,則表中數(shù)據(jù)為:

顯而易見(jiàn),說(shuō)明兩個(gè)方法統(tǒng)一都沒(méi)有事務(wù)

若加上,則只插入了一條數(shù)據(jù)

說(shuō)明外部方法還是存在事務(wù)的,只要出現(xiàn)異常就會(huì)回滾。而被調(diào)用方 transactionB.testNotSupported() 的方法內(nèi)部不支持事務(wù),于是該方法出錯(cuò)之后也不會(huì)出現(xiàn)事務(wù)回滾,因此出錯(cuò)之前的插表操作就沒(méi)有回滾

5.異常被catch住了,沒(méi)有拋出來(lái)

由于事務(wù)默認(rèn)回滾的是:RuntimeException 和 Error 兩種情況,所以以下兩種情況都會(huì)失效

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

/**
* 7、異常被吃了:try掉異常(未拋出),事務(wù)失效
*/
@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("執(zhí)行失敗:"+e.getMessage());
// throw new RuntimeException("執(zhí)行失敗,拋出異常:"+e.getMessage());
}
}

也就是說(shuō),異常并沒(méi)有被拋出來(lái),而是通過(guò) catch 住,然后做了一些其他的邏輯處理,這種事務(wù)是不會(huì)生效的

再來(lái)看看第二種情況

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

@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("執(zhí)行失敗:"+e.getMessage());
throw new Exception("拋出了Exception異常:"+e.getMessage());
// throw new RuntimeException("執(zhí)行失敗,拋出異常:"+e.getMessage());
}
}

回想一下我們的大前提:Spring事務(wù)默認(rèn)回滾的是:RuntimeException和Error兩種情況。現(xiàn)在拋出了 Excption ,就不會(huì)觸發(fā)事務(wù)的回滾,所以這樣事務(wù)也是不生效的

要怎樣才能讓這樣的事務(wù)生效呢?

改成拋出 RuntimeException 事務(wù)就生效啦~ 你完全可以現(xiàn)在就試試

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

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

小結(jié)

只要抓住一點(diǎn):事務(wù)默認(rèn)在:RuntimeException 和 Error 兩種情況下執(zhí)行回滾操作

因此,

1)異常被捕獲掉,沒(méi)有拋出來(lái),就不會(huì)生效

2)拋出的 RuntimeException 異常或者未遇到 Error ,事務(wù)默認(rèn)也不會(huì)生效的

那么,怎么處理才能讓事務(wù)生效,想必已經(jīng)很明顯了吧?

6.未啟用spring事務(wù)管理功能

@EnableTransactionManagement 注解用來(lái)啟用spring事務(wù)自動(dòng)管理事務(wù)的功能,只有有這個(gè)注解,這個(gè)注解千萬(wàn)不要忘記寫(xiě)了

但是當(dāng)引入了;

spring-boot-starter-jdbc

就可以不用我們自己寫(xiě),為什么呢?我們來(lái)看看;

@EnableTransactionManagement 這個(gè)注解開(kāi)啟事務(wù),其實(shí)和我們自己使用@EnableTransactionManagement是一樣的 因此,只要我們?cè)?SpringBoot 中引入了 spring-boot-starter-jdbc 這個(gè)依賴(lài)以后,我們就只需要使用 @Transactional 就可以了。

二、總而言之

好了,本篇文章,接著上一篇的事務(wù)基礎(chǔ),為大家演示了幾個(gè)開(kāi)發(fā)過(guò)程中容易出現(xiàn)的事務(wù)失效,或者事務(wù)不能按照自己的預(yù)期來(lái)執(zhí)行的幾種場(chǎng)景。

總結(jié)一下,日常中最容易出現(xiàn)事務(wù)失效或者不能按照預(yù)期執(zhí)行的情況,大致分為四類(lèi):自身調(diào)用、異常被吃、異常拋出類(lèi)型不對(duì)以及事務(wù)的傳播機(jī)制不熟悉。

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

很簡(jiǎn)單,只需要關(guān)注單個(gè)方法時(shí)事務(wù)的回滾機(jī)制,以及涉及到兩個(gè)以及兩個(gè)以上方法的調(diào)用時(shí)事務(wù)的傳播機(jī)制以及Spring事務(wù)的原理。

  • 單個(gè)方法的調(diào)用,事務(wù)只會(huì)在執(zhí)行過(guò)程中出現(xiàn) RuntimeException 和 Error 以及事務(wù)超時(shí)時(shí)進(jìn)行事務(wù)的回滾;
  • 多個(gè)方法:當(dāng)在同一個(gè)類(lèi)中進(jìn)行方法調(diào)用時(shí),若要事務(wù)不失效,則需要在調(diào)用方的方法都加上事務(wù)注解,同時(shí)需要關(guān)注事務(wù)的傳播機(jī)制以及各層方法的事務(wù)回滾情況;

不在同一類(lèi)中時(shí),則需要根據(jù)特定的業(yè)務(wù)場(chǎng)景,選擇不同的傳播機(jī)制。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2025-02-10 00:27:54

2024-04-01 08:05:27

Go開(kāi)發(fā)Java

2023-03-13 13:36:00

Go擴(kuò)容切片

2019-09-25 15:30:15

2025-05-27 08:45:00

2019-10-30 14:44:41

Prometheus開(kāi)源監(jiān)控系統(tǒng)

2018-09-11 09:14:52

面試公司缺點(diǎn)

2025-04-29 10:17:42

2025-10-15 02:45:00

系統(tǒng)分表接口

2017-07-17 15:46:20

Oracle并行機(jī)制

2023-09-08 08:52:12

Spring注解事務(wù)

2023-08-29 10:51:44

2022-07-06 11:47:27

JAVAfor循環(huán)

2025-07-08 09:09:32

MySQL類(lèi)型

2025-04-14 09:31:03

2025-08-26 01:20:00

2025-11-26 07:52:31

2019-12-12 14:32:26

SQL語(yǔ)句數(shù)據(jù)庫(kù)

2025-06-03 06:30:05

2025-02-06 07:45:44

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

久久精品超碰| 国产一级爱c视频| 欧美成人国产一区二区| 一本色道久久综合亚洲精品婷婷| 日韩爱爱小视频| 涩涩视频在线| 久久99高清| 成人在线视频www| 激情小说亚洲一区| 日韩欧美国产网站| 一本久久精品一区二区| 欧美日韩国产999| 精品一卡二卡三卡四卡日本乱码| 国产欧美日韩高清| 欧美精品v日韩精品v国产精品| 91超碰在线电影| 亚洲精品高清无码视频| 狠狠97人人婷婷五月| 区一区二日本| 国产午夜亚洲精品一级在线| 欧产日产国产精品视频| 久久午夜精品| 欧美xxxxxxxx| 在线播放的av| 国产精品久久久久久久久搜平片| 亚洲第一导航| 野花国产精品入口| 国产激情美女久久久久久吹潮| 欧美人与牛zoz0性行为| 欧美精品久久久久久久| 亚洲福利影视| 少妇av一区二区三区| 欧美aaaxxxx做受视频| 欧美视频三区在线播放| 污视频网站在线免费观看| 国产精品理论片| 成人性视频欧美一区二区三区| 国产电影一区在线| dy888午夜| 国产在线精品一区二区夜色| 午夜精品一区二区三区四区| 六月丁香婷婷色狠狠久久| 亚洲 国产 欧美一区| 青青草精品视频| 亚洲精品成人a8198a| 麻豆视频一区二区| 超碰97在线看| 99综合电影在线视频| 免费国产a级片| 国产欧美日韩精品一区| 91国内精品在线视频| 亚洲一区二区三区爽爽爽爽爽| 三级黄色网址| 国产一区二区三区四区五区在线| 中国精品18videos性欧美| 91在线观看免费高清完整版在线观看 | 日韩精品一区在线| 3d玉蒲团在线观看| 欧美一区二区三区四区在线观看| 青春草免费在线视频| 精品亚洲一区二区| 高清一区二区中文字幕| 2025国产精品视频| 欧美电影免费播放| 国产美女精品在线观看| 日本特黄久久久高潮| 精品久久久久久无码中文野结衣| 99r精品视频| 东北一级毛片| 欧美在线观看你懂的| a级大胆欧美人体大胆666| 日韩在线视频二区| 欧美猛男同性videos| 国产一区二区三区色淫影院| 国产一区二区三区观看| 国产精品入口免费软件| 精品国产精品自拍| f2c人成在线观看免费视频| 在线电影av不卡网址| 日韩美女毛片| 精品中文字幕一区| av高清久久久| 伊大人久久香线焦宗合一75大| 日韩精品一区二区三区swag| 日韩免费精品| 国产视频一区二区不卡| 99久免费精品视频在线观看 | 欧美午夜视频| 日本在线观看一区二区| 97se亚洲国产综合自在线观| aaa大片免费观看| 欧美顶级少妇做爰| 国产人与zoxxxx另类91| 91天堂在线视频| 国产精品18久久久| 污黄视频在线看| 亚洲欧美一区二区三区久久| 精品日本12videosex| 中文字幕日韩一区二区三区| 中文字幕亚洲区| 色戒汤唯在线| 国产精品夜色7777狼人| 国产精品888| 久久99久久| 在线日韩欧美视频| 欧美午夜国产| 一区二区三区视频在线观看免费| 91精品国产91久久久久久一区二区| 伊人久久大香伊蕉在人线观看热v 伊人久久大香线蕉综合影院首页 伊人久久大香 | 日韩中文字幕a| 欧美午夜视频在线观看| 日韩一区二区三区免费视频| 国产精品视频一区二区三区四| 国产成人在线网站| 福利在线视频导航| 国语自产精品视频在线看| 美女视频黄a大片欧美| 欧美性猛交p30| 深夜福利一区二区| 亚洲欧美bt| 天天干夜夜干| 久久九九亚洲综合| 免费欧美日韩国产三级电影| 四虎影视精品成人| 久久6精品影院| 国产在线国偷精品产拍免费yy| 欧美18xxxxx| 欧美一级淫片播放口| 国产乱码精品一品二品| 欧美另类极品| 91欧美激情另类亚洲| 中文字幕五月欧美| 成人激情久久| 久艹在线免费观看| 日韩精品视频在线| 欧美亚洲视频| 日本在线免费网| 97中文在线| 欧美色另类天堂2015| 国产精品三级| 99热在线免费观看| 久热精品视频在线观看| 国产成人午夜精品影院观看视频 | 亚洲啊v在线| 成人写真福利网| 亚洲一区二区三区中文字幕在线| 亚洲一区视频在线| 亚洲精品伦理| 热色播在线视频| 亚洲欧美色图片| 亚洲免费网址| 国产亚洲依依| 91免费国产视频| 五月天亚洲精品| 奇米色欧美一区二区三区| 国产又大又黄又粗的视频| 日韩中文字幕久久| 高清成人免费视频| 先锋欧美三级| 国产日韩亚洲欧美在线| 日韩男女性生活视频| 黑人一区二区三区| 精品成在人线av无码免费看| 久久久久久久久免费视频| 国产成人精品网站| 综合久久给合久久狠狠狠97色| 天堂精品久久久久| 在线观看av网页| 性欧美在线看片a免费观看| 中文字幕成人在线观看| 91国内精品白嫩初高生| 中文字幕 91| 57pao成人国产永久免费| 国产精品丝袜91| 天堂日韩电影| 最近97中文超碰在线| 亚洲在线观看视频| 欧美日韩一区二区三区四区五区| 狠久久av成人天堂| 欧美另类tv| 久久国产午夜精品理论片最新版本| 亚洲小视频在线观看| 成人午夜精品在线| aaa国产精品视频| 美女被人操视频在线观看| av在线不卡一区| 精品国产a毛片| 成人高清视频在线| 你懂的在线观看一区二区| 在线免费观看黄色片| 欧美二级三级| 日韩小视频网址| 一区二区三区在线不卡| 亚洲精品色图| 国产精品亚洲d| www.男人的天堂.com| 粉嫩高清一区二区三区精品视频 | 亚洲欧洲自拍| 欧美96一区二区免费视频| 黄色成年人视频在线观看|