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

Java?Spring事務(wù)管理超詳細(xì)指南

 更新時(shí)間:2026年01月14日 10:14:32   作者:無(wú)名-CODING  
Spring的事務(wù)管理提供了聲明式事務(wù)管理,支持聲明式事務(wù)的控制,簡(jiǎn)化了事務(wù)管理的復(fù)雜性,下面這篇文章主要介紹了Java?Spring事務(wù)管理的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

一、 引言:為什么我們需要事務(wù)?

1.1 一個(gè)經(jīng)典的轉(zhuǎn)賬場(chǎng)景

想象一下,你正在使用手機(jī)銀行給朋友轉(zhuǎn)賬 100 塊錢(qián)。這個(gè)動(dòng)作在代碼層面通常分為兩步:

  1. 你的賬戶(hù)扣款 100 元 (UPDATE account SET balance = balance - 100 WHERE id = A)
  2. 朋友的賬戶(hù)增加 100 元 (UPDATE account SET balance = balance + 100 WHERE id = B)

如果發(fā)生了意外會(huì)怎樣?

  • 假如第一步執(zhí)行成功了,你的錢(qián)扣了。
  • 緊接著,程序報(bào)錯(cuò)了(比如斷網(wǎng)了、數(shù)據(jù)庫(kù)崩了、或者代碼拋異常了)。
  • 結(jié)果:你的錢(qián)沒(méi)了,朋友也沒(méi)收到錢(qián)!?? 這就是嚴(yán)重的數(shù)據(jù)不一致問(wèn)題。

1.2 事務(wù)的作用

為了解決這個(gè)問(wèn)題,數(shù)據(jù)庫(kù)引入了 事務(wù)(Transaction) 的概念。
事務(wù)就是把一組數(shù)據(jù)庫(kù)操作看作一個(gè)整體。這個(gè)整體內(nèi)的操作,要么全部成功,要么全部失敗(回滾),不允許出現(xiàn) “做一半” 的情況。

二、 事務(wù)的四大特性(ACID)

這是面試必考題!理解這四個(gè)詞,就理解了事務(wù)的靈魂。

特性英文解釋通俗理解
原子性Atomicity事務(wù)是不可分割的最小單位,要么全做,要么全不做。要么大家都成功,要么大家一起"死"(回滾),不能有幸存者。
一致性Consistency事務(wù)執(zhí)行前后,數(shù)據(jù)必須保持合規(guī)的邏輯狀態(tài)。轉(zhuǎn)賬前 A+B=200,轉(zhuǎn)賬后 A+B 還是 200,錢(qián)不會(huì)憑空消失或變多。
隔離性Isolation多個(gè)事務(wù)并發(fā)執(zhí)行時(shí),互不干擾。我在操作這條數(shù)據(jù)時(shí),你別來(lái)?yè)v亂(具體看隔離級(jí)別)。
持久性Durability事務(wù)一旦提交,修改就是永久的,即使系統(tǒng)崩潰也不丟失。落子無(wú)悔,寫(xiě)進(jìn)硬盤(pán)了,斷電也沒(méi)事。

三、 Spring 中的事務(wù)管理

在 Java 開(kāi)發(fā)中,我們幾乎都在使用 Spring 框架來(lái)管理事務(wù)。Spring 提供了兩種方式:

  1. 編程式事務(wù):在代碼里手動(dòng)寫(xiě) commit(), rollback()(代碼侵入性太強(qiáng),現(xiàn)在很少用了)。
  2. 聲明式事務(wù):使用注解 @Transactional,把繁瑣的事務(wù)邏輯交給 Spring 代理處理(推薦,最常用)。

3.1 快速入門(mén)代碼示例

下面是一個(gè)典型的 Service 層代碼,演示了如何使用 @Transactional

package com.example.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.mapper.AccountMapper;

@Service
public class AccountService {

    @Autowired
    private AccountMapper accountMapper;

    /**
     * 轉(zhuǎn)賬方法
     * 
     * @Transactional 注解說(shuō)明:
     * 1. 這是一個(gè)事務(wù)方法。
     * 2. Spring 會(huì)自動(dòng)在方法開(kāi)始前開(kāi)啟事務(wù)(Begin)。
     * 3. 如果方法正常執(zhí)行結(jié)束,Spring 自動(dòng)提交事務(wù)(Commit)。
     * 4. 如果方法拋出了 RuntimeException (運(yùn)行時(shí)異常),Spring 自動(dòng)回滾事務(wù)(Rollback)。
     */
    @Transactional(rollbackFor = Exception.class) // 建議:顯式指定遇到任何異常都回滾
    public void transfer(Long fromId, Long toId, Double amount) {
        
        // 1. 扣錢(qián) (可能發(fā)生異常的地方)
        accountMapper.decreaseBalance(fromId, amount);
        System.out.println("用戶(hù) " + fromId + " 扣款成功");

        // 模擬一個(gè)意外異常:例如除以零,或者空指針
        // int i = 1 / 0; 
        // 如果上面這行解開(kāi)注釋?zhuān)麄€(gè)事務(wù)會(huì)回滾,第一步扣的錢(qián)會(huì)加回去。

        // 2. 加錢(qián)
        accountMapper.increaseBalance(toId, amount);
        System.out.println("用戶(hù) " + toId + " 入賬成功");
        
        // 方法結(jié)束 -> 提交事務(wù)
    }
}

四、 核心難點(diǎn):事務(wù)的傳播行為 (Propagation)

“傳播行為” 是 Spring 特有的概念,解決的是 Service 方法互相調(diào)用 時(shí),事務(wù)該怎么算的問(wèn)題。
比如:方法 A 調(diào)用了 方法 B,由于 A 和 B 上都有 @Transactional 注解,那 B 是加入 A 的事務(wù)?還是自己新開(kāi)一個(gè)?

Spring 定義了 7 種傳播行為,最常用的有下面 3 種:

1. REQUIRED (默認(rèn)值)

?? 口語(yǔ)解釋:“有就加入,沒(méi)有就新建。”

  • 場(chǎng)景:如果不指定,默認(rèn)就是這個(gè)。
  • 行為
    • 如果 A 已經(jīng)開(kāi)啟了事務(wù),B 就加入 A 的事務(wù)(它倆是同一條船上的螞蚱,要么一起成功,要么一起回滾)。
    • 如果 A 沒(méi)有事務(wù),B 就自己開(kāi)啟一個(gè)新的事務(wù)。

2. REQUIRES_NEW

?? 口語(yǔ)解釋:“不管你有沒(méi)有,我都自己玩。”

  • 場(chǎng)景:記錄日志操作。不管業(yè)務(wù)邏輯成功還是失敗,日志都必須記錄下來(lái),不能因?yàn)闃I(yè)務(wù)回滾了日志也就沒(méi)了。
  • 行為
    • B 方法會(huì)掛起 A 的事務(wù),自己開(kāi)啟一個(gè)全新的事務(wù)。
    • B 的成功失敗,不影響 A;A 的回滾,也不影響 B(前提是 B 已經(jīng)提交了)。
    • 代碼示例
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logOperation() {
        // 這里的操作在一個(gè)完全獨(dú)立的事務(wù)中
        logMapper.insertLog("操作發(fā)生");
    }
    

3. NESTED (嵌套事務(wù))

?? 口語(yǔ)解釋:“你是父,我是子。你掛我也掛,我掛你不一定掛。”

  • 行為
    • 基于數(shù)據(jù)庫(kù)的 Savepoint(保存點(diǎn))技術(shù)。
    • B 是 A 的一個(gè)子事務(wù)。如果 A 回滾,B 一定回滾。
    • 但是如果 B 異常回滾了,A 可以選擇捕獲異常,繼續(xù)執(zhí)行其他邏輯,不一定要回滾。

五、 核心難點(diǎn):事務(wù)的隔離級(jí)別 (Isolation)

當(dāng)很多用戶(hù)同時(shí)操作數(shù)據(jù)庫(kù)時(shí)(高并發(fā)),會(huì)產(chǎn)生一些奇怪的現(xiàn)象。通過(guò)設(shè)置隔離級(jí)別來(lái)權(quán)衡數(shù)據(jù)的準(zhǔn)確性和性能。

5.1 并發(fā)可能導(dǎo)致的問(wèn)題

  1. 臟讀 (Dirty Read):讀到了別人還沒(méi)提交的數(shù)據(jù)。(最嚴(yán)重,絕對(duì)不允許)
    • 例子:A 沒(méi)提交轉(zhuǎn)賬,B 讀到了錢(qián)多了,結(jié)果 A 回滾了,B 讀到的是假數(shù)據(jù)。
  2. 不可重復(fù)讀 (Non-repeatable Read):在一個(gè)事務(wù)里,兩次讀取同一行數(shù)據(jù),結(jié)果不一樣(因?yàn)橹虚g被別人改了)。
    • 例子:我看庫(kù)存是 1,準(zhǔn)備買(mǎi),中間被別人買(mǎi)走了,我再看庫(kù)存變成 0 了。
  3. 幻讀 (Phantom Read):在一個(gè)事務(wù)里,兩次查詢(xún)通過(guò)同樣的條件,結(jié)果條數(shù)不一樣(因?yàn)橹虚g別人插入/刪除了數(shù)據(jù))。

5.2 SQL 標(biāo)準(zhǔn)的四個(gè)隔離級(jí)別

級(jí)別名稱(chēng)解決的問(wèn)題性能
READ_UNCOMMITTED讀未提交啥也沒(méi)解決,可能臟讀最高(極不安全)
READ_COMMITTED讀已提交解決了臟讀 (Oracle/SQLServer 默認(rèn))較好
REPEATABLE_READ可重復(fù)讀解決了臟讀、不可重復(fù)讀 (MySQL 默認(rèn))一般
SERIALIZABLE串行化解決了所有問(wèn)題 (完全排隊(duì)執(zhí)行)最差(像單線程)

?? Spring 配置方式
@Transactional(isolation = Isolation.REPEATABLE_READ)

六、 常見(jiàn)坑點(diǎn):為什么我的 @Transactional 失效了?

這是新手最容易遇到的問(wèn)題,代碼寫(xiě)了注解,但異常拋出時(shí)數(shù)據(jù)居然沒(méi)有回滾!常見(jiàn)原因如下:

  1. 方法不是 public 的:Spring 默認(rèn)只代理 public 方法。
  2. 同類(lèi)內(nèi)部調(diào)用
    • 錯(cuò)誤示范:方法 A 調(diào) 方法 B,A 沒(méi)有注解,B 有注解。在 Controller 調(diào) A 時(shí),B 的事務(wù)不會(huì)生效。
    • 原因:Spring 事務(wù)是基于 AOP 代理 的,同類(lèi)內(nèi)部調(diào)用 this.methodB() 是直接調(diào)用原始對(duì)象的方法,繞過(guò)了 Spring 的代理對(duì)象,所以事務(wù)沒(méi)開(kāi)啟。
  3. 異常被你自己 catch 吃了
    • 錯(cuò)誤示范:
      @Transactional
      public void method() {
          try {
              // 業(yè)務(wù)代碼
          } catch (Exception e) {
              e.printStackTrace(); 
              // ? 錯(cuò)誤!這里把異常捕獲了,Spring 以為代碼執(zhí)行正常,就會(huì)提交事務(wù)!
          }
      }
      
    • 修正:在 catch 塊里 throw new RuntimeException(e) 或者手動(dòng)回滾 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();。
  4. 數(shù)據(jù)庫(kù)引擎不支持:例如 MySQL 的 MyISAM 引擎是不支持事務(wù)的,必須用 InnoDB。

七、 高頻面試題 QA

Q1:Spring 事務(wù)默認(rèn)回滾什么異常?

A:默認(rèn)只回滾 RuntimeException(運(yùn)行時(shí)異常)和 Error。對(duì)于 Exception(受檢異常,如 IOException),默認(rèn)是不回滾的。
追問(wèn):怎么讓受檢異常也回滾?
A:配置 @Transactional(rollbackFor = Exception.class)

Q2:REQUIRED 和 REQUIRES_NEW 的區(qū)別?

A

  • REQUIRED:如果當(dāng)前有事務(wù),就加入;如果沒(méi)有,就新建。多個(gè)方法共用一個(gè)物理事務(wù),一起提交或回滾。
  • REQUIRES_NEW:無(wú)論當(dāng)前有沒(méi)有事務(wù),都掛起當(dāng)前事務(wù),自己開(kāi)啟一個(gè)新事務(wù)。兩個(gè)事務(wù)互不影響,是隔離的。

Q3:什么是 Spring 的事務(wù)失效?舉個(gè)例子。

A:最經(jīng)典的就是自調(diào)用問(wèn)題。在同一個(gè) Service 類(lèi)中,非事務(wù)方法 A 調(diào)用事務(wù)方法 B,導(dǎo)致 B 的事務(wù)失效。因?yàn)?Spring AOP 生成代理對(duì)象時(shí),只有通過(guò)代理對(duì)象調(diào)用方法才能攔截事務(wù),內(nèi)部 this 調(diào)用直接走了目標(biāo)對(duì)象。

Q4:ACID 是靠什么保證的?(進(jìn)階)

A

  • A (原子性):靠 undo log (回滾日志) 保證,失敗了可以回滾。
  • C (一致性):是最終目的,靠代碼邏輯和 AID 共同保證。
  • I (隔離性):靠 MVCC (多版本并發(fā)控制) 和 機(jī)制保證。
  • D (持久性):靠 redo log (重做日志) 保證,斷電也能恢復(fù)。

八、 總結(jié)

事務(wù)管理是后端開(kāi)發(fā)的"安全帶"。雖然 Spring Boot 讓我們使用 @Transactional 一個(gè)注解就能搞定事務(wù),但作為開(kāi)發(fā)者,我們必須深入理解其背后的傳播機(jī)制隔離級(jí)別,才能在復(fù)雜的業(yè)務(wù)場(chǎng)景下寫(xiě)出健壯的代碼。

到此這篇關(guān)于Java Spring事務(wù)管理的文章就介紹到這了,更多相關(guān)Java Spring事務(wù)管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)Excel批量導(dǎo)入數(shù)據(jù)

    Java實(shí)現(xiàn)Excel批量導(dǎo)入數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)Excel批量導(dǎo)入數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • SpringBoot整合DeepSeek技術(shù)指南(實(shí)際應(yīng)用場(chǎng)景)

    SpringBoot整合DeepSeek技術(shù)指南(實(shí)際應(yīng)用場(chǎng)景)

    這篇文章主要介紹了SpringBoot整合DeepSeek技術(shù)指南,本文通過(guò)實(shí)際應(yīng)用場(chǎng)景模擬給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-04-04
  • 一個(gè)Servlet是如何處理多個(gè)請(qǐng)求的?

    一個(gè)Servlet是如何處理多個(gè)請(qǐng)求的?

    以前我一直以為一個(gè)Servlet只能處理一個(gè)請(qǐng)求,后來(lái)發(fā)現(xiàn)是自己太菜了,可以借助攜帶一個(gè)參數(shù)來(lái)完成多個(gè)請(qǐng)求的處理,根據(jù)參數(shù)的不同,在核心的service方法中調(diào)用不同的業(yè)務(wù)方法,來(lái)實(shí)現(xiàn)處理多個(gè)servlet請(qǐng)求的目的,廢話(huà)不多說(shuō),直接上代碼,需要的朋友可以參考下
    2021-06-06
  • mybatis多層嵌套resultMap及返回自定義參數(shù)詳解

    mybatis多層嵌套resultMap及返回自定義參數(shù)詳解

    這篇文章主要介紹了mybatis多層嵌套resultMap及返回自定義參數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • SpringBoot淺析安全管理之Spring Security配置

    SpringBoot淺析安全管理之Spring Security配置

    安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會(huì)發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會(huì)出現(xiàn)問(wèn)題,這篇文章主要介紹了SpringBoot安全管理Spring Security基本配置
    2022-08-08
  • Java服務(wù)端服務(wù)監(jiān)控:Prometheus與Spring Boot Actuator的集成方式

    Java服務(wù)端服務(wù)監(jiān)控:Prometheus與Spring Boot Actuator的集成方式

    本文介紹了如何將Prometheus與SpringBootActuator集成,實(shí)現(xiàn)對(duì)Java服務(wù)端應(yīng)用的監(jiān)控,通過(guò)集成,可以利用Prometheus的強(qiáng)大監(jiān)控能力,及時(shí)發(fā)現(xiàn)和解決性能問(wèn)題
    2024-12-12
  • SpringCloud Ribbon負(fù)載均衡代碼實(shí)例

    SpringCloud Ribbon負(fù)載均衡代碼實(shí)例

    這篇文章主要介紹了SpringCloud Ribbon負(fù)載均衡代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • SpringBoot中配置雙數(shù)據(jù)源的實(shí)現(xiàn)示例

    SpringBoot中配置雙數(shù)據(jù)源的實(shí)現(xiàn)示例

    在許多應(yīng)用程序中,可能會(huì)遇到需要連接多個(gè)數(shù)據(jù)庫(kù)的情況,本文主要介紹了SpringBoot中配置雙數(shù)據(jù)源的實(shí)現(xiàn)示例,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • Java?Mybatis框架由淺入深全解析下篇

    Java?Mybatis框架由淺入深全解析下篇

    MyBatis是一個(gè)優(yōu)秀的持久層框架,它對(duì)jdbc的操作數(shù)據(jù)庫(kù)的過(guò)程進(jìn)行封裝,使開(kāi)發(fā)者只需要關(guān)注SQL本身,而不需要花費(fèi)精力去處理例如注冊(cè)驅(qū)動(dòng)、創(chuàng)建connection、創(chuàng)建statement、手動(dòng)設(shè)置參數(shù)、結(jié)果集檢索等jdbc繁雜的過(guò)程代碼,本文將作為最終篇為大家介紹MyBatis的使用
    2022-07-07
  • 怎么在AVD上安裝apk軟件

    怎么在AVD上安裝apk軟件

    執(zhí)行 Windows 開(kāi)始菜單 => 所有程序 => 附件 => 命令提示符 或通過(guò) Win+R 組合鍵調(diào)出 運(yùn)行 對(duì)話(huà)框輸入cmd 單擊確定即可
    2013-09-09

最新評(píng)論

郑州市| 铁岭县| 湘西| 南开区| 南澳县| 梁河县| 邵阳县| 宁强县| 台湾省| 华亭县| 皮山县| 万山特区| 久治县| 望都县| 乐东| 梁平县| 响水县| 静海县| 嘉鱼县| 凤阳县| 阿瓦提县| 西峡县| 库尔勒市| 湘阴县| 丘北县| 渭源县| 漳州市| 沅陵县| 霍林郭勒市| 青神县| 寿阳县| 芜湖市| 荆门市| 饶平县| 思茅市| 田东县| 云浮市| 海阳市| 定陶县| 定南县| 拜泉县|