最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring聲明式事務(wù)@Transactional的用法解讀

 更新時(shí)間:2025年05月06日 09:03:16   作者:棕豆兔&  
這篇文章主要介紹了Spring聲明式事務(wù)@Transactional的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Spring 聲明式事務(wù) @Transactional的使用很簡(jiǎn)單,只需要添加依賴,在需要的方法或者類上添加 @Transactional注解即可。

一、添加依賴

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-tx</artifactId>
</dependency>

在需要事務(wù)的方法上添加 @Transactional 注解就可以實(shí)現(xiàn)了,無(wú)需手動(dòng)開啟事務(wù)和提交事務(wù),進(jìn)入方法時(shí)自動(dòng)開啟事務(wù),方法執(zhí)行完會(huì)自動(dòng)提交事務(wù),如果中途發(fā)生了沒有處理的異常會(huì)自動(dòng)回滾事務(wù)。

代碼示例:

@RequestMapping("/trans")
@RestController
public class TransactionalController {

 @Autowired
 private UserService userService;

 @Transactional
 @RequestMapping("/registry")
 public String registry(String name,String password){
 //用戶注冊(cè)
 userService.registryUser(name,password);
 return "注冊(cè)成功";
 }
}

假設(shè)代碼有異常:

@Slf4j
@RequestMapping("/trans")
@RestController
public class TransactionalController {

 @Autowired
 private UserService userService;

 @Transactional
 @RequestMapping("/registry")
 public String registry(String name,String password){
 //?戶注冊(cè)
 userService.registryUser(name,password);
 log.info("用戶數(shù)據(jù)插?成功");
 //強(qiáng)制程序拋出異常
 int a = 10/0;
 return "注冊(cè)成功";
 }
}

啟動(dòng)項(xiàng)目發(fā)現(xiàn)雖然日志顯示數(shù)據(jù)插入成功,但數(shù)據(jù)庫(kù)卻沒有新增數(shù)據(jù),事務(wù)進(jìn)行了回滾。

二、@Transactional 作用

@Transactional 可以用來(lái)修飾方法或類:

  • 修飾方法時(shí): 只有修飾public 方法時(shí)才生效(修飾其他方法時(shí)不會(huì)報(bào)錯(cuò), 也不生效)[推薦]
  • 修飾類時(shí): 對(duì) @Transactional 修飾的類中所有的 public 方法都生效。

方法/類被 @Transactional 注解修飾時(shí),在目標(biāo)方法執(zhí)行開始之前,會(huì)自動(dòng)開啟事務(wù),方法執(zhí)行結(jié)束之后,自動(dòng)提交事務(wù)。

  • 如果在方法執(zhí)行過(guò)程中,出現(xiàn)異常,且異常未被捕獲,就進(jìn)行事務(wù)回滾操作。
  • 如果異常被程序捕獲,方法就被認(rèn)為是成功執(zhí)行,依然會(huì)提交事務(wù)。

舉例:(對(duì)異常進(jìn)行捕獲)

@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
 //??注冊(cè)
 userService.registryUser(name,password);
 log.info("??數(shù)據(jù)插?成功");
 //對(duì)異常進(jìn)?捕獲
 try {
 //強(qiáng)制程序拋出異常
 int a = 10/0;
 }catch (Exception e){
 e.printStackTrace();
 }
 return "注冊(cè)成功";
}

運(yùn)行程序,發(fā)現(xiàn)雖然程序出錯(cuò)了,但是由于異常被捕獲,所以事務(wù)依然得到了提交。

如果需要事務(wù)進(jìn)行回滾,有以下兩種方式:

  • 重新拋出異常
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//?戶注冊(cè)
userService.registryUser(name,password);
log.info("??數(shù)據(jù)插?成功");
 //對(duì)異常進(jìn)?捕獲
 try {
 //強(qiáng)制程序拋出異常
 int a = 10/0;
 }catch (Exception e){
 //將異常重新拋出去
 throw e;
 }
 return "注冊(cè)成功";
}
  • 手動(dòng)回滾事務(wù)

使用TransactionAspectSupport.currentTransactionStatus() 得到當(dāng)前的事務(wù),并使用用 setRollbackOnly 設(shè)置 setRollbackOnly。

@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//?戶注冊(cè)
userService.registryUser(name,password);
log.info("?戶數(shù)據(jù)插?成功");
//對(duì)異常進(jìn)行捕獲
try {
//強(qiáng)制程序拋出異常
int a = 10/0;
}catch (Exception e){
// 手動(dòng)回滾事務(wù)
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return "注冊(cè)成功";
}

三、@Transactional詳解

@Transactional注解有三個(gè)常見的屬性:

  • rollbackFor: 異?;貪L屬性。指定能夠觸發(fā)事務(wù)回滾的異常類型,可以指定多個(gè)異常類型。
  • isolation: 事務(wù)的隔離級(jí)別。默認(rèn)值為 Isolation.DEFAULT
  • propagation: 事務(wù)的傳播機(jī)制。默認(rèn)值為 Propagation.REQUIRED

3.1 rollbackFor

@Transactional 默認(rèn)只在遇到運(yùn)行時(shí)異常和Error時(shí)才會(huì)回滾,非運(yùn)行時(shí)異常不回滾。即

Exception的子類中,除了RuntimeException及其子類。

如果需要所有異常都回滾,需要來(lái)配置 @Transactional 注解當(dāng)中的 rollbackFor 屬性,通過(guò)rollbackFor 這個(gè)屬性指定出現(xiàn)何種異常類型時(shí)事務(wù)進(jìn)行回滾。

@Transactional(rollbackFor = Exception.class)
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {

 //?戶注冊(cè)
 userService.registryUser(name,password);
 log.info("?戶數(shù)據(jù)插?成功");
 if (true){
 throw new IOException();
 }
 return "r2";
}

運(yùn)行程序會(huì)發(fā)現(xiàn)雖然程序拋出了異常,但是事務(wù)依然進(jìn)行了提交。

3.2 事務(wù)隔離級(jí)別

事務(wù)隔離級(jí)別解決的是多個(gè)事務(wù)同時(shí)調(diào)用一個(gè)數(shù)據(jù)庫(kù)的問(wèn)題:

Spring 中事務(wù)隔離級(jí)別有 5 種:

  • Isolation.DEFAULT : 以連接的數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別為主;
  • Isolation.READ_UNCOMMITTED : 讀未提交,對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 READ UNCOMMITTED;
  • Isolation.READ_COMMITTED : 讀已提交,對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 READ COMMITTED;
  • Isolation.REPEATABLE_READ : 可重復(fù)讀,對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 REPEATABLE READ;
  • Isolation.SERIALIZABLE : 串行化,對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 SERIALIZABLE。
public enum Isolation {
 DEFAULT(-1),
 READ_UNCOMMITTED(1),
 READ_COMMITTED(2),
 REPEATABLE_READ(4),
 SERIALIZABLE(8);
 private final int value;
 private Isolation(int value) {
 this.value = value;
 }
 public int value() {
 return this.value;
 }
}

Spring 中事務(wù)隔離級(jí)別可以通過(guò) @Transactional 中的 isolation 屬性進(jìn)行設(shè)置:

@Transactional(isolation = Isolation.READ_COMMITTED)
@RequestMapping("/r3")
public String r3(String name,String password) throws IOException {
 //... 
 return "r3";
}

3.3 Spring 事務(wù)傳播機(jī)制

事務(wù)傳播機(jī)制就是: 多個(gè)事務(wù)方法存在調(diào)用關(guān)系時(shí),事務(wù)是如何在這些方法間進(jìn)行傳播的。

事務(wù)傳播機(jī)制解決的是一個(gè)事務(wù)在多個(gè)節(jié)點(diǎn)(方法)中傳遞的問(wèn)題:

@Transactional 注解支持事務(wù)傳播機(jī)制的設(shè)置, 通過(guò) propagation 屬性來(lái)指定傳播行為。

Spring 事務(wù)傳播機(jī)制有以下 7 種:

  • Propagation.REQUIRED:默認(rèn)的事務(wù)傳播級(jí)別。如果當(dāng)前存在事務(wù), 則加入該事務(wù)。如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù).
  • Propagation.SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù)。如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
  • Propagation.MANDATORY:強(qiáng)制性。如果當(dāng)前存在事務(wù), 則加入該事務(wù)。如果當(dāng)前沒有事務(wù),則拋出異常。
  • Propagation.REQUIRES_NEW : 創(chuàng)建一個(gè)新的事務(wù)。如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。也就是說(shuō)不管外部方法是否開啟事務(wù),Propagation.REQUIRES_NEW 修飾的內(nèi)部方法都會(huì)新開啟自己的事務(wù),且開啟的事務(wù)相互獨(dú)立,互不干擾。
  • Propagation.NOT_SUPPORTED : 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起(不用)。
  • Propagation.NEVER : 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù), 則拋出異常。
  • Propagation.NESTED : 如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行。如果當(dāng)前沒有事務(wù),則該取值等價(jià)于 PROPAGATION_REQUIRED。
public enum Propagation {
 REQUIRED(0),
 SUPPORTS(1),
 MANDATORY(2),
 REQUIRES_NEW(3),
 NOT_SUPPORTED(4),
 NEVER(5),
 NESTED(6);
 private final int value;
 private Propagation(int value) {
 this.value = value;
 }
 public int value() {
 return this.value;
 }
}

NESTED 和 REQUIRED 區(qū)別:

  • 整個(gè)事務(wù)如果全部執(zhí)行成功,二者的結(jié)果是一樣的。
  • 如果事務(wù)一部分執(zhí)行成功,REQUIRED加入事務(wù)會(huì)導(dǎo)致整個(gè)事務(wù)全部回滾。NESTED嵌套事務(wù)可以實(shí)現(xiàn)局部回滾,不會(huì)影響上一個(gè)方法中執(zhí)行的結(jié)果。

一個(gè)非常形象的比喻:

比如一對(duì)新人要結(jié)婚了, 關(guān)于是否需要房子:

  • 1. Propagation.REQUIRED : 需要有房子。 如果你有房,我們就一起住,如果你沒房,我們就一起買房。(如果當(dāng)前存在事務(wù),則加入該事務(wù)。如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù))
  • 2. Propagation.SUPPORTS : 可以有房子。如果你有房, 那就一起住。如果沒房,那就租房。 (如果當(dāng)前存在事務(wù),則加入該事務(wù)。如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行)
  • 3. Propagation.MANDATORY : 必須有房子。要求必須有房,如果沒房就不結(jié)婚。(如果當(dāng)前存在事務(wù), 則加?該事務(wù)。如果當(dāng)前沒有事務(wù),則拋出異常)
  • 4. Propagation.REQUIRES_NEW : 必須買新房。不管你有沒有房,必須要兩個(gè)人一起買房。即使有房也不住。(創(chuàng)建一個(gè)新的事務(wù). 如果當(dāng)前存在事務(wù), 則把當(dāng)前事務(wù)掛起)
  • 5. Propagation.NOT_SUPPORTED : 不需要房。不管你有沒有房, 我都不住,必須租房。(以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起)
  • 6. Propagation.NEVER : 不能有房子。(以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常)
  • 7. Propagation.NESTED : 如果你沒房,就一起買房。如果你有房,我們就以房子為根據(jù)地。做點(diǎn)生意。(如果如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行。如果當(dāng)前沒有事務(wù),則該取值等價(jià)于 PROPAGATION_REQUIRED )

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Java多線程和IO流的應(yīng)用

    詳解Java多線程和IO流的應(yīng)用

    這篇文章主要介紹了詳解Java多線程和IO流的應(yīng)用,無(wú)論是本地文件復(fù)制,還是網(wǎng)絡(luò)多線程下載,對(duì)于流的使用都是一樣的,需要的朋友可以參考下
    2023-04-04
  • 深入理解JDK8中Stream使用

    深入理解JDK8中Stream使用

    Stream 是 Java8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對(duì)集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過(guò)濾和映射數(shù)據(jù)等操作。這篇文章主要介紹了JDK8中Stream使用解析,需要的朋友可以參考下
    2021-06-06
  • 使用Mybatis-plus清空表數(shù)據(jù)的操作方法

    使用Mybatis-plus清空表數(shù)據(jù)的操作方法

    MyBatis 是一個(gè)基于 java 的持久層框架,它內(nèi)部封裝了 jdbc,極大提高了我們的開發(fā)效率,文中給大家介紹了MybatisPlus常用API-增刪改查功能,感興趣的朋友跟隨小編一起看看吧
    2022-11-11
  • MyBatis之foreach標(biāo)簽的用法及多種循環(huán)問(wèn)題

    MyBatis之foreach標(biāo)簽的用法及多種循環(huán)問(wèn)題

    這篇文章主要介紹了MyBatis之foreach標(biāo)簽的用法及多種循環(huán)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 使用Mybatis對(duì)數(shù)據(jù)庫(kù)進(jìn)行單表操作的實(shí)現(xiàn)示例

    使用Mybatis對(duì)數(shù)據(jù)庫(kù)進(jìn)行單表操作的實(shí)現(xiàn)示例

    這篇文章主要介紹了使用Mybatis對(duì)數(shù)據(jù)庫(kù)進(jìn)行單表操作的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • SpringBoot配置HTTPS的詳細(xì)步驟

    SpringBoot配置HTTPS的詳細(xì)步驟

    本文介紹了配置SpringBoot項(xiàng)目HTTPS的全流程,包括開發(fā)環(huán)境生成自簽名證書和生產(chǎn)環(huán)境配置正式SSL證書,以及配置HTTP自動(dòng)跳轉(zhuǎn)HTTPS以提升用戶體驗(yàn),注意事項(xiàng)和常見問(wèn)題也一并進(jìn)行了說(shuō)明,需要的朋友可以參考下
    2026-03-03
  • SpringBoot讀取外部配置文件的方法

    SpringBoot讀取外部配置文件的方法

    這篇文章主要介紹了SpringBoot讀取外部配置文件的方法,以端口配置為例,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • 詳解Spring中接口的bean是如何注入的

    詳解Spring中接口的bean是如何注入的

    這篇文章主要介紹了詳解Spring中接口的bean是如何注入的的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 類似微信說(shuō)話功能的錄音處理代碼分享

    類似微信說(shuō)話功能的錄音處理代碼分享

    這篇文章主要介紹了類似微信中說(shuō)話功能的錄音處理代碼,需要大家自己加UI界面,大家參考使用吧
    2014-01-01
  • Java如何利用策略模式替代if/else語(yǔ)句

    Java如何利用策略模式替代if/else語(yǔ)句

    這篇文章主要介紹了Java如何利用策略模式替代if/else語(yǔ)句,幫助大家優(yōu)化自己的代碼,提高程序運(yùn)行效率,感興趣的朋友可以了解下
    2020-09-09

最新評(píng)論

宁海县| 建阳市| 科技| 荣成市| 林芝县| 岳阳市| 进贤县| 平安县| 洛阳市| 宜兰县| 南岸区| 泸水县| 财经| 丰县| 辰溪县| 定安县| 垫江县| 永善县| 思南县| 凤冈县| 沐川县| 鄄城县| 怀宁县| 蓬莱市| 呼玛县| 肇东市| 乌审旗| 和硕县| 海晏县| 天等县| 晋城| 凤冈县| 都昌县| 城市| 齐河县| 八宿县| 安福县| 巴南区| 满城县| 吴江市| 贺州市|