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

Java事務失效八大場景詳細解析

 更新時間:2025年10月23日 08:47:41   作者:xiaoye3708  
在Java開發(fā)中Spring框架提供了強大的事務管理功能,然而在實際開發(fā)過程中,由于對框架特性的誤解或不當使用,可能導致事務失效問題,這篇文章主要介紹了Java事務失效八大場景的相關資料,需要的朋友可以參考下

前言

在 Java 開發(fā)中,事務管理是保證數據一致性的核心機制,尤其是在 Spring 框架中,@Transactional注解的使用極大簡化了事務配置。然而,在實際開發(fā)中,事務常常會因為一些細節(jié)問題而失效,導致數據異常。本文將詳細解析 Java 事務失效的八大場景,每個場景都提供代碼示例與對應的修復方案。

一、事務方法非 public 修飾

失效原理

Spring 的@Transactional注解默認只對public方法生效。這是因為 Spring AOP 在實現事務管理時,無論是 JDK 動態(tài)代理還是 CGLIB 代理,都無法對非 public 方法(private、protected、默認訪問權限)進行有效的事務增強。

失效代碼

java運行

@Service
public class UserService {
    // 非public方法,事務注解失效
    @Transactional
    void updateUser(Long id) { 
        userMapper.updateStatus(id, 1);
    }
}

修復方案

將事務方法修改為public訪問權限。

修復后代碼

java運行

@Service
public class UserService {
    // 修改為public方法,事務生效
    @Transactional
    public void updateUser(Long id) { 
        userMapper.updateStatus(id, 1);
    }
}

二、異常被捕獲且未重新拋出

失效原理

Spring 事務默認僅在遇到未捕獲的RuntimeExceptionError時觸發(fā)回滾。如果方法內部使用try-catch捕獲了異常且未重新拋出,事務管理器會認為沒有異常發(fā)生,從而不會執(zhí)行回滾操作。

失效代碼

java運行

@Service
public class OrderService {
    @Transactional
    public void createOrder(Order order) {
        try {
            orderMapper.insert(order);
            // 模擬異常
            int i = 1 / 0;
        } catch (Exception e) {
            // 捕獲異常但未拋出,事務不會回滾
            log.error("創(chuàng)建訂單失敗", e);
        }
    }
}

修復方案

方案一:捕獲異常后重新拋出
方案二:使用TransactionAspectSupport手動觸發(fā)回滾

修復后代碼(方案一)

java運行

@Service
public class OrderService {
    @Transactional
    public void createOrder(Order order) {
        try {
            orderMapper.insert(order);
            // 模擬異常
            int i = 1 / 0;
        } catch (Exception e) {
            log.error("創(chuàng)建訂單失敗", e);
            // 重新拋出異常,觸發(fā)事務回滾
            throw new RuntimeException("創(chuàng)建訂單失敗", e);
        }
    }
}

修復后代碼(方案二)

java運行

@Service
public class OrderService {
    @Transactional
    public void createOrder(Order order) {
        try {
            orderMapper.insert(order);
            // 模擬異常
            int i = 1 / 0;
        } catch (Exception e) {
            log.error("創(chuàng)建訂單失敗", e);
            // 手動觸發(fā)事務回滾
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
}

三、錯誤配置 rollbackFor 屬性

失效原理

@TransactionalrollbackFor屬性用于指定需要回滾的異常類型,默認值為{RuntimeException.class, Error.class}。如果業(yè)務中拋出的是受檢查異常(如IOException、SQLException),且未在rollbackFor中聲明,事務不會回滾。

失效代碼

java運行

@Service
public class FileService {
    // 未指定rollbackFor,受檢查異常不會觸發(fā)回滾
    @Transactional
    public void importData(String filePath) throws IOException {
        // 讀取文件(可能拋出IOException)
        FileReader reader = new FileReader(filePath);
        // 數據入庫操作
        dataMapper.batchInsert(parseData(reader));
    }
}

修復方案

顯式指定rollbackFor屬性,包含需要回滾的異常類型。

修復后代碼

java運行

@Service
public class FileService {
    // 顯式指定rollbackFor包含IOException
    @Transactional(rollbackFor = {IOException.class, RuntimeException.class})
    public void importData(String filePath) throws IOException {
        FileReader reader = new FileReader(filePath);
        dataMapper.batchInsert(parseData(reader));
    }
}

// 更通用的方式:捕獲所有Exception
@Service
public class FileService {
    @Transactional(rollbackFor = Exception.class)
    public void importData(String filePath) throws IOException {
        // 業(yè)務邏輯不變
    }
}

四、事務傳播機制配置不當

失效原理

Spring 事務的傳播機制決定了事務方法之間的嵌套行為。若傳播機制配置不合理(如使用NOT_SUPPORTEDSUPPORTS等),可能導致操作不在事務中執(zhí)行。

失效代碼

java運行

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService;
    
    @Transactional
    public void createOrder(Order order) {
        orderMapper.insert(order);
        // 調用支付服務(非事務方式執(zhí)行)
        paymentService.processPayment(order.getId(), order.getAmount());
    }
}

@Service
public class PaymentService {
    // 配置為非事務方式執(zhí)行
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void processPayment(Long orderId, BigDecimal amount) {
        paymentMapper.insert(new Payment(orderId, amount));
        // 若此處發(fā)生異常,不會回滾
    }
}

修復方案

根據業(yè)務需求選擇合適的傳播機制,常用的是默認的REQUIRED(如果當前有事務則加入,否則創(chuàng)建新事務)。

修復后代碼

java運行

@Service
public class PaymentService {
    // 使用默認傳播機制REQUIRED
    @Transactional
    public void processPayment(Long orderId, BigDecimal amount) {
        paymentMapper.insert(new Payment(orderId, amount));
    }
}

五、同類方法內部調用

失效原理

Spring 事務基于 AOP 代理實現,事務增強邏輯在代理對象中執(zhí)行。若同一個類中的方法 A 調用方法 B(B 有@Transactional注解),由于調用未經過代理對象,方法 B 的事務注解會失效。

失效代碼

java運行

@Service
public class UserService {
    // 方法A(無事務)調用方法B(有事務)
    public void updateUserInfo(Long id, String name, Integer age) {
        updateUserName(id, name);  // 內部調用,事務失效
        updateUserAge(id, age);    // 內部調用,事務失效
    }
    
    @Transactional
    public void updateUserName(Long id, String name) {
        userMapper.updateName(id, name);
    }
    
    @Transactional
    public void updateUserAge(Long id, Integer age) {
        userMapper.updateAge(id, age);
    }
}

修復方案

方案一:將方法拆分到不同的類中
方案二:通過AopContext獲取代理對象調用

修復后代碼(方案二)

java運行

// 1. 首先在啟動類開啟暴露代理
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)  // 關鍵配置
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 2. 在Service中通過代理對象調用
@Service
public class UserService {
    public void updateUserInfo(Long id, String name, Integer age) {
        // 通過AopContext獲取代理對象
        UserService proxy = (UserService) AopContext.currentProxy();
        proxy.updateUserName(id, name);  // 代理對象調用,事務生效
        proxy.updateUserAge(id, age);    // 代理對象調用,事務生效
    }
    
    @Transactional
    public void updateUserName(Long id, String name) {
        userMapper.updateName(id, name);
    }
    
    @Transactional
    public void updateUserAge(Long id, Integer age) {
        userMapper.updateAge(id, age);
    }
}

六、數據庫不支持事務

失效原理

事務最終依賴數據庫支持。若使用的數據庫引擎不支持事務(如 MySQL 的MyISAM引擎),即使代碼中配置了事務,也無法生效。

失效場景

sql

-- 使用MyISAM引擎創(chuàng)建表,不支持事務
CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

此時即使 Service 層配置了@Transactional,數據庫操作也不會有事務保障。

修復方案

使用支持事務的數據庫引擎(如 MySQL 的InnoDB)。

修復后代碼

sql

-- 使用InnoDB引擎創(chuàng)建表,支持事務
CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

七、未被 Spring 容器管理

失效原理

若事務所在的類未被 Spring 容器掃描并實例化(如未加@Service、@Component等注解),@Transactional注解會因沒有代理對象而失效。

失效代碼

java運行

// 未加@Service注解,未被Spring管理
public class ProductService {
    @Autowired
    private ProductMapper productMapper;
    
    @Transactional
    public void updateStock(Long productId, Integer quantity) {
        productMapper.decreaseStock(productId, quantity);
    }
}

修復方案

為類添加 Spring 注解(如@Service),確保其被 Spring 容器管理。

修復后代碼

java運行

// 添加@Service注解,被Spring容器管理
@Service
public class ProductService {
    @Autowired
    private ProductMapper productMapper;
    
    @Transactional
    public void updateStock(Long productId, Integer quantity) {
        productMapper.decreaseStock(productId, quantity);
    }
}

八、多線程場景下的事務隔離

失效原理

在事務方法中啟動新線程執(zhí)行數據庫操作時,新線程的操作不會納入當前事務管理(線程間事務上下文獨立)。即使主線程事務回滾,新線程的操作也可能已提交。

失效代碼

java運行

@Service
public class BatchService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LogMapper logMapper;
    
    @Transactional
    public void batchProcess(List<Long> userIds) {
        // 主線程操作
        userMapper.batchUpdateStatus(userIds, 1);
        
        // 新線程執(zhí)行日志記錄(不在當前事務中)
        new Thread(() -> {
            logMapper.insert(new Log("批量處理用戶: " + userIds));
        }).start();
    }
}

修復方案

避免在事務方法中使用多線程執(zhí)行數據庫操作,或使用分布式事務協(xié)調機制。

修復后代碼

java運行

@Service
public class BatchService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LogMapper logMapper;
    
    @Transactional
    public void batchProcess(List<Long> userIds) {
        // 主線程操作
        userMapper.batchUpdateStatus(userIds, 1);
        
        // 同一事務中執(zhí)行日志記錄
        logMapper.insert(new Log("批量處理用戶: " + userIds));
    }
}

總結

事務失效的核心原因通常與以下幾點相關:

  • 代理機制限制(非 public 方法、同類內部調用)
  • 異常處理不當(捕獲未拋出、未配置 rollbackFor)
  • 事務屬性配置錯誤(傳播機制不合理)
  • 基礎環(huán)境問題(數據庫不支持、未被 Spring 管理)
  • 并發(fā)場景下的事務隔離問題

在實際開發(fā)中,需結合業(yè)務場景合理配置事務屬性,同時注意編碼規(guī)范,避免上述陷阱,才能確保事務機制有效運行,保障數據一致性。

到此這篇關于Java事務失效八大場景的文章就介紹到這了,更多相關Java事務失效場景內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 解決IDEA新建xml文件顯示為普通的text文本問題

    解決IDEA新建xml文件顯示為普通的text文本問題

    IntelliJ IDEA新建XML文件時顯示為普通文本,可以通過以下步驟解決:1.檢查項目文件過濾器,確保沒有隱藏XML文件類型;2.在XML文件中添加或修改文件類型關聯(lián);3.如果問題依然存在,檢查并刪除自定義的文件類型過濾器
    2024-11-11
  • java生成sm2/hutool生成公鑰私鑰代碼示例

    java生成sm2/hutool生成公鑰私鑰代碼示例

    這篇文章主要給大家介紹了關于java生成sm2/hutool生成公鑰私鑰的相關資料,Java是一種廣泛使用的編程語言,可以用來生成公鑰和私鑰文件,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-09-09
  • Spring Boot 的注解生效詳細步驟解析

    Spring Boot 的注解生效詳細步驟解析

    Spring通過掃描、解析、注冊分層處理配置類注解(如@Configuration、@ComponentScan等),利用遞歸、延遲加載和緩存機制,實現BeanDefinition的動態(tài)注冊與靈活擴展,解決依賴和性能問題,本文給大家介紹Spring Boot的注解生效詳細步驟解析,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • SpringBoot+Mybatis實現Mapper接口與Sql綁定幾種姿勢

    SpringBoot+Mybatis實現Mapper接口與Sql綁定幾種姿勢

    通常我們在使用Mybatis進行開發(fā)時,會選擇xml文件來寫對應的sql,然后將Mapper接口與sql的xml文件建立綁定關系,然后在項目中調用mapper接口就可以執(zhí)行對應的sql,感興趣的可以學習一下
    2021-09-09
  • Java 泛型詳解之類型參數的力量(最新推薦)

    Java 泛型詳解之類型參數的力量(最新推薦)

    本文系統(tǒng)講解了Java泛型的定義、使用、通配符、邊界及常見陷阱,強調了泛型在Java編程中的重要性,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-10-10
  • SpringBoot整合MyBatisPlus配置動態(tài)數據源的方法

    SpringBoot整合MyBatisPlus配置動態(tài)數據源的方法

    這篇文章主要介紹了SpringBoot整合MyBatisPlus配置動態(tài)數據源的方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-05-05
  • Java的Channel通道之FileChannel類詳解

    Java的Channel通道之FileChannel類詳解

    這篇文章主要介紹了Java的Channel通道之FileChannel類詳解,FileChannel類是Java NIO中的一個重要類,用于在文件中進行讀寫操作,它提供了一種高效的方式來處理大文件和隨機訪問文件的需求,需要的朋友可以參考下
    2023-10-10
  • 如何用nacos搭建微服務注冊配置中心

    如何用nacos搭建微服務注冊配置中心

    這篇文章主要介紹了如何用nacos搭建微服務注冊配置中心問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Mybatis 中的sql批量修改方法實現

    Mybatis 中的sql批量修改方法實現

    在項目中遇到需要批量更新的功能,原本想的是在Java中用循環(huán)訪問數據庫去更新,但是心里總覺得這樣做會不會太頻繁了,太耗費資源了,效率也很低,查了下mybatis的批量操作,原來確實有<foreach>標簽可以做到,下面通過本文給大家介紹下
    2017-01-01
  • Spring自帶定時任務@Scheduled注解實例講解

    Spring自帶定時任務@Scheduled注解實例講解

    這篇文章主要介紹了Spring自帶定時任務@Scheduled注解的相關知識,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-06-06

最新評論

金溪县| 博兴县| 东兰县| 仁怀市| 四川省| 林口县| 海丰县| 渝中区| 万州区| 株洲市| 安多县| 安化县| 永昌县| 普陀区| 吉木萨尔县| 常州市| 婺源县| 海林市| 山东省| 天长市| 固始县| 淮滨县| 灵璧县| 桐柏县| 吉木萨尔县| 启东市| 仁怀市| 周宁县| 张家界市| 任丘市| 凌海市| 专栏| 竹山县| 永善县| 天镇县| 博野县| 屯昌县| 建宁县| 二连浩特市| 板桥市| 万山特区|