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

Spring事務(wù)失效的十大陷阱與終極解決方案

 更新時(shí)間:2025年10月23日 09:26:42   作者:初見(jiàn)001  
本文將全面剖析Spring事務(wù)失效的各種場(chǎng)景,提供完整的代碼示例和解決方案,幫你徹底掌握事務(wù)管理的精髓,感興趣的小伙伴跟著小編一起來(lái)看看吧

1. 事務(wù)管理基礎(chǔ):Spring事務(wù)工作原理深度解析

在深入問(wèn)題之前,我們先完整理解Spring聲明式事務(wù)的工作機(jī)制:

1.1 Spring事務(wù)架構(gòu)概覽

// Spring事務(wù)管理的核心組件關(guān)系
@Component
public class TransactionArchitecture {
    /*
     * 事務(wù)管理核心流程:
     * 1. 解析@Transactional注解
     * 2. 創(chuàng)建AOP代理
     * 3. 事務(wù)攔截器處理
     * 4. 事務(wù)管理器協(xié)調(diào)
     * 5. 連接資源管理
     */
}

// 事務(wù)攔截器核心邏輯(簡(jiǎn)化版)
public class TransactionInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 1. 獲取事務(wù)屬性
        TransactionAttribute txAttr = getTransactionAttributeSource()
            .getTransactionAttribute(invocation.getMethod(), invocation.getClass());
        
        // 2. 創(chuàng)建或加入事務(wù)
        TransactionStatus status = transactionManager.getTransaction(txAttr);
        
        try {
            // 3. 執(zhí)行業(yè)務(wù)方法
            Object result = invocation.proceed();
            
            // 4. 提交事務(wù)
            transactionManager.commit(status);
            return result;
        } catch (Exception ex) {
            // 5. 回滾處理
            completeTransactionAfterThrowing(txAttr, status, ex);
            throw ex;
        }
    }
}

1.2 完整的事務(wù)配置示例

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = 
            new DataSourceTransactionManager(dataSource);
        
        // 完整的事務(wù)管理器配置
        transactionManager.setNestedTransactionAllowed(true);
        transactionManager.setRollbackOnCommitFailure(false);
        transactionManager.setDefaultTimeout(30); // 30秒超時(shí)
        
        return transactionManager;
    }
    
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
        TransactionTemplate template = new TransactionTemplate(transactionManager);
        template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        template.setTimeout(30);
        return template;
    }
}

2. 陷阱一:同類方法調(diào)用(最常見(jiàn)的坑)

2.1 問(wèn)題完整復(fù)現(xiàn)

@Service
@Slf4j
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private InventoryService inventoryService;
    
    /**
     * 創(chuàng)建訂單的主方法
     */
    public OrderCreateResult createOrder(OrderCreateRequest request) {
        log.info("開(kāi)始創(chuàng)建訂單: {}", request.getOrderNo());
        
        // 1. 驗(yàn)證訂單
        validateOrder(request);
        
        // 2. 保存訂單(期望在事務(wù)中)
        Order order = saveOrder(request);  // ? 事務(wù)失效點(diǎn)
        
        // 3. 更新庫(kù)存
        updateInventory(order);
        
        // 4. 記錄日志
        logOrderCreate(order);
        
        return new OrderCreateResult(true, "創(chuàng)建成功", order.getId());
    }
    
    /**
     * 保存訂單數(shù)據(jù) - 期望在事務(wù)中執(zhí)行
     */
    @Transactional
    public Order saveOrder(OrderCreateRequest request) {
        log.info("保存訂單數(shù)據(jù)");
        
        Order order = convertToOrder(request);
        order.setStatus(OrderStatus.CREATED);
        
        // 保存訂單主表
        Order savedOrder = orderRepository.save(order);
        
        // 保存訂單明細(xì)
        saveOrderItems(request.getItems(), savedOrder.getId());
        
        // 模擬一個(gè)業(yè)務(wù)異常
        if (request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("訂單金額必須大于0");
        }
        
        return savedOrder;
    }
    
    /**
     * 保存訂單明細(xì)
     */
    @Transactional(propagation = Propagation.REQUIRED)
    private void saveOrderItems(List<OrderItem> items, Long orderId) {
        for (OrderItem item : items) {
            item.setOrderId(orderId);
            orderRepository.saveItem(item);
        }
    }
    
    /**
     * 更新庫(kù)存
     */
    private void updateInventory(Order order) {
        inventoryService.deductInventory(order);
    }
    
    /**
     * 記錄訂單創(chuàng)建日志
     */
    private void logOrderCreate(Order order) {
        // 記錄操作日志
        System.out.println("訂單創(chuàng)建完成: " + order.getId());
    }
}

2.2 問(wèn)題深度分析

/**
 * 問(wèn)題分析服務(wù) - 通過(guò)AOP原理解釋為什么事務(wù)失效
 */
@Component
@Aspect
@Slf4j
public class TransactionAnalysisAspect {
    
    /**
     * 模擬Spring AOP代理的工作方式
     */
    public void demonstrateProxyMechanism() {
        /*
         * 實(shí)際Spring創(chuàng)建的代理對(duì)象結(jié)構(gòu):
         * 
         * ProxyOrderService (Spring AOP代理)
         *   - target: RealOrderService (原始對(duì)象)
         *   - advisors: [TransactionInterceptor]
         * 
         * 當(dāng)調(diào)用 proxy.saveOrder() 時(shí):
         *   1. 代理攔截方法調(diào)用
         *   2. 執(zhí)行TransactionInterceptor
         *   3. 開(kāi)啟事務(wù)
         *   4. 調(diào)用target.saveOrder()
         *   5. 提交/回滾事務(wù)
         * 
         * 當(dāng)在同一個(gè)類中調(diào)用 this.saveOrder() 時(shí):
         *   1. 直接調(diào)用原始對(duì)象的方法
         *   2. 繞過(guò)代理攔截器
         *   3. 事務(wù)注解失效
         */
    }
    
    @Around("@annotation(transactional)")
    public Object analyzeTransaction(ProceedingJoinPoint joinPoint, 
                                   Transactional transactional) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        boolean isTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
        
        log.info("方法 {} 調(diào)用前,事務(wù)狀態(tài): {}", methodName, isTransactionActive);
        
        Object result = joinPoint.proceed();
        
        isTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
        log.info("方法 {} 調(diào)用后,事務(wù)狀態(tài): {}", methodName, isTransactionActive);
        
        return result;
    }
}

2.3 完整解決方案

@Service
@Slf4j
public class CorrectOrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Autowired
    private ApplicationContext applicationContext;
    
    /**
     * 方案1:通過(guò)ApplicationContext獲取代理對(duì)象
     */
    public OrderCreateResult createOrderV1(OrderCreateRequest request) {
        validateOrder(request);
        
        // 獲取代理對(duì)象
        CorrectOrderService proxy = applicationContext.getBean(CorrectOrderService.class);
        Order order = proxy.saveOrder(request);  // ? 通過(guò)代理調(diào)用
        
        updateInventory(order);
        logOrderCreate(order);
        
        return new OrderCreateResult(true, "創(chuàng)建成功", order.getId());
    }
    
    /**
     * 方案2:自我注入代理對(duì)象
     */
    @Autowired
    @Lazy  // 避免循環(huán)依賴問(wèn)題
    private CorrectOrderService self;
    
    public OrderCreateResult createOrderV2(OrderCreateRequest request) {
        validateOrder(request);
        
        Order order = self.saveOrder(request);  // ? 通過(guò)注入的代理調(diào)用
        
        updateInventory(order);
        logOrderCreate(order);
        
        return new OrderCreateResult(true, "創(chuàng)建成功", order.getId());
    }
    
    /**
     * 方案3:重構(gòu)方法結(jié)構(gòu),事務(wù)方法作為入口
     */
    @Transactional
    public OrderCreateResult createOrderV3(OrderCreateRequest request) {
        validateOrder(request);
        
        Order order = saveOrderInternal(request);  // ? 在事務(wù)方法內(nèi)調(diào)用
        
        updateInventory(order);
        logOrderCreate(order);
        
        return new OrderCreateResult(true, "創(chuàng)建成功", order.getId());
    }
    
    /**
     * 方案4:使用編程式事務(wù)
     */
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public OrderCreateResult createOrderV4(OrderCreateRequest request) {
        validateOrder(request);
        
        Order order = transactionTemplate.execute(status -> {
            try {
                return saveOrderInternal(request);
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });
        
        updateInventory(order);
        logOrderCreate(order);
        
        return new OrderCreateResult(true, "創(chuàng)建成功", order.getId());
    }
    
    @Transactional
    public Order saveOrder(OrderCreateRequest request) {
        return saveOrderInternal(request);
    }
    
    /**
     * 內(nèi)部保存邏輯 - 不添加事務(wù)注解
     */
    private Order saveOrderInternal(OrderCreateRequest request) {
        log.info("保存訂單數(shù)據(jù)");
        
        Order order = convertToOrder(request);
        order.setStatus(OrderStatus.CREATED);
        
        Order savedOrder = orderRepository.save(order);
        saveOrderItems(request.getItems(), savedOrder.getId());
        
        if (request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("訂單金額必須大于0");
        }
        
        return savedOrder;
    }
    
    // 其他輔助方法...
    private void saveOrderItems(List<OrderItem> items, Long orderId) {
        for (OrderItem item : items) {
            item.setOrderId(orderId);
            orderRepository.saveItem(item);
        }
    }
    
    private void validateOrder(OrderCreateRequest request) {
        // 驗(yàn)證邏輯
    }
    
    private void updateInventory(Order order) {
        inventoryService.deductInventory(order);
    }
    
    private void logOrderCreate(Order order) {
        // 日志記錄
    }
}

3. 陷阱二:異常處理不當(dāng)

3.1 異常處理完整示例

@Service
@Slf4j
public class ExceptionHandlingService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private EmailService emailService;
    
    /**
     * 場(chǎng)景1:捕獲異常導(dǎo)致事務(wù)不回滾
     */
    @Transactional
    public void registerUserV1(User user) {
        try {
            // 保存用戶
            userRepository.save(user);
            
            // 發(fā)送歡迎郵件(可能拋出異常)
            emailService.sendWelcomeEmail(user.getEmail());
            
        } catch (Exception e) {
            // ? 捕獲了所有異常,事務(wù)不會(huì)回滾
            log.error("用戶注冊(cè)失敗: {}", user.getUsername(), e);
            // 用戶記錄已保存,但郵件發(fā)送失敗,數(shù)據(jù)不一致
        }
    }
    
    /**
     * 場(chǎng)景2:檢查異常默認(rèn)不回滾
     */
    @Transactional
    public void uploadUserAvatarV1(User user, InputStream avatarStream) throws IOException {
        userRepository.update(user);
        
        // 上傳頭像(拋出IOException)
        fileService.uploadAvatar(user.getId(), avatarStream);  // ? IOException不會(huì)觸發(fā)回滾
        
        // 如果上傳失敗,用戶信息已更新,但頭像缺失
    }
    
    /**
     * 場(chǎng)景3:錯(cuò)誤的異常類型指定
     */
    @Transactional(rollbackFor = RuntimeException.class) // 默認(rèn)值,但業(yè)務(wù)異??赡芾^承Exception
    public void processBusinessV1(BusinessRequest request) {
        userRepository.updateStatus(request.getUserId(), "PROCESSING");
        
        // 業(yè)務(wù)處理,拋出自定義業(yè)務(wù)異常
        businessService.process(request);  // ? 如果BusinessException繼承Exception,不會(huì)回滾
        
        userRepository.updateStatus(request.getUserId(), "COMPLETED");
    }
    
    /**
     * 正確解決方案
     */
    
    /**
     * 方案1:正確配置回滾異常
     */
    @Transactional(rollbackFor = Exception.class) // ? 所有異常都回滾
    public void registerUserV2(User user) {
        try {
            userRepository.save(user);
            emailService.sendWelcomeEmail(user.getEmail());
            
        } catch (EmailException e) {
            // 只捕獲郵件發(fā)送異常,不影響事務(wù)
            log.warn("歡迎郵件發(fā)送失敗: {}", user.getEmail(), e);
            // 郵件發(fā)送失敗不影響用戶注冊(cè),事務(wù)繼續(xù)提交
            
        } catch (Exception e) {
            // 其他異常重新拋出,觸發(fā)回滾
            log.error("用戶注冊(cè)失敗: {}", user.getUsername(), e);
            throw new BusinessException("用戶注冊(cè)失敗", e);
        }
    }
    
    /**
     * 方案2:分層異常處理
     */
    @Transactional(rollbackFor = BusinessException.class)
    public void uploadUserAvatarV2(User user, InputStream avatarStream) {
        try {
            userRepository.update(user);
            fileService.uploadAvatar(user.getId(), avatarStream);
            
        } catch (IOException e) {
            // 將檢查異常轉(zhuǎn)換為運(yùn)行時(shí)異常
            throw new BusinessException("頭像上傳失敗", e);
        }
    }
    
    /**
     * 方案3:編程式異??刂?
     */
    @Transactional
    public void processBusinessV2(BusinessRequest request) {
        TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
        
        try {
            userRepository.updateStatus(request.getUserId(), "PROCESSING");
            businessService.process(request);
            userRepository.updateStatus(request.getUserId(), "COMPLETED");
            
        } catch (BusinessException e) {
            // 手動(dòng)標(biāo)記回滾
            status.setRollbackOnly();
            log.error("業(yè)務(wù)處理失敗: {}", request.getRequestId(), e);
            throw e;
        }
    }
    
    /**
     * 方案4:自定義異常回滾策略
     */
    @Component
    public class CustomRollbackPolicy {
        
        @Autowired
        private PlatformTransactionManager transactionManager;
        
        public void executeWithRollbackPolicy(Runnable businessLogic, 
                                            Class<? extends Exception>... rollbackExceptions) {
            DefaultTransactionAttribute transactionAttribute = new DefaultTransactionAttribute();
            transactionAttribute.setRollbackRules(Arrays.asList(rollbackExceptions));
            
            TransactionStatus status = transactionManager.getTransaction(transactionAttribute);
            
            try {
                businessLogic.run();
                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                throw e;
            }
        }
    }
}

4. 陷阱三:事務(wù)傳播機(jī)制誤用

4.1 傳播機(jī)制完整示例

@Service
@Slf4j
public class PropagationService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private LogRepository logRepository;
    
    @Autowired
    private PropagationService self;
    
    /**
     * 錯(cuò)誤示例:錯(cuò)誤使用REQUIRED傳播
     */
    @Transactional
    public void processBatchOrdersV1(List<Order> orders) {
        int successCount = 0;
        int failureCount = 0;
        
        for (Order order : orders) {
            try {
                // ? 每個(gè)訂單處理在同一個(gè)事務(wù)中
                processSingleOrder(order);
                successCount++;
                
            } catch (Exception e) {
                failureCount++;
                log.error("訂單處理失敗: {}", order.getOrderNo(), e);
                // 一個(gè)訂單失敗會(huì)導(dǎo)致整個(gè)批次回滾
            }
        }
        
        log.info("批次處理完成: 成功={}, 失敗={}", successCount, failureCount);
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void processSingleOrder(Order order) {
        // 訂單處理邏輯
        orderRepository.save(order);
        inventoryService.deductStock(order);
        
        if (order.getAmount().compareTo(BigDecimal.valueOf(10000)) > 0) {
            throw new BusinessException("訂單金額超限");
        }
    }
    
    /**
     * 正確使用傳播機(jī)制
     */
    
    /**
     * 方案1:使用REQUIRES_NEW實(shí)現(xiàn)事務(wù)隔離
     */
    public BatchProcessResult processBatchOrdersV2(List<Order> orders) {
        BatchProcessResult result = new BatchProcessResult();
        
        for (Order order : orders) {
            try {
                // ? 每個(gè)訂單在獨(dú)立事務(wù)中處理
                self.processSingleOrderInNewTx(order);
                result.incrementSuccess();
                
            } catch (Exception e) {
                result.incrementFailure();
                log.error("訂單處理失敗: {}", order.getOrderNo(), e);
                // 單個(gè)訂單失敗不影響其他訂單
            }
        }
        
        // 記錄批次日志(在獨(dú)立事務(wù)中)
        self.logBatchResult(result);
        
        return result;
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processSingleOrderInNewTx(Order order) {
        orderRepository.save(order);
        inventoryService.deductStock(order);
        
        if (order.getAmount().compareTo(BigDecimal.valueOf(10000)) > 0) {
            throw new BusinessException("訂單金額超限");
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logBatchResult(BatchProcessResult result) {
        logRepository.saveBatchLog(result);
    }
    
    /**
     * 方案2:使用NESTED傳播(需要支持保存點(diǎn))
     */
    @Transactional
    public void processOrderWithNestedOperations(Order order) {
        // 主訂單處理
        orderRepository.save(order);
        
        try {
            // ? 嵌套事務(wù):可以獨(dú)立回滾
            self.processOrderItems(order.getItems());
        } catch (Exception e) {
            log.error("訂單明細(xì)處理失敗,繼續(xù)處理其他邏輯", e);
            // 明細(xì)處理失敗不影響主訂單
        }
        
        // 繼續(xù)處理其他邏輯
        updateOrderStatistics(order);
    }
    
    @Transactional(propagation = Propagation.NESTED)
    public void processOrderItems(List<OrderItem> items) {
        for (OrderItem item : items) {
            itemRepository.save(item);
            
            if (item.getQuantity() <= 0) {
                throw new BusinessException("商品數(shù)量必須大于0");
            }
        }
    }
    
    /**
     * 方案3:使用NOT_SUPPORTED暫停事務(wù)
     */
    @Transactional
    public void generateReportWithHeavyOperation() {
        // 輕量級(jí)數(shù)據(jù)庫(kù)操作
        List<ReportData> data = reportRepository.getReportData();
        
        // ? 暫停事務(wù),執(zhí)行重量級(jí)操作
        String reportFile = self.generateLargeReportFile(data);
        
        // 恢復(fù)事務(wù),保存報(bào)告記錄
        reportRepository.saveReportRecord(reportFile);
    }
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String generateLargeReportFile(List<ReportData> data) {
        // 生成大型報(bào)告文件(耗時(shí)操作)
        // 不在事務(wù)中,避免長(zhǎng)事務(wù)和鎖競(jìng)爭(zhēng)
        return reportService.generateExcelReport(data);
    }
    
    /**
     * 傳播機(jī)制使用指南
     */
    public class PropagationGuide {
        /*
         * REQUIRED(默認(rèn)):如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)
         * 適用場(chǎng)景:大多數(shù)業(yè)務(wù)方法
         * 
         * REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起
         * 適用場(chǎng)景:需要獨(dú)立提交/回滾的子任務(wù)
         * 
         * NESTED:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)
         * 適用場(chǎng)景:可部分回滾的子操作
         * 
         * SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行
         * 適用場(chǎng)景:查詢方法,可有可無(wú)事務(wù)
         * 
         * NOT_SUPPORTED:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起
         * 適用場(chǎng)景:非事務(wù)性操作,如文件處理、遠(yuǎn)程調(diào)用
         * 
         * NEVER:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常
         * 適用場(chǎng)景:強(qiáng)制非事務(wù)環(huán)境
         * 
         * MANDATORY:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則拋出異常
         * 適用場(chǎng)景:強(qiáng)制要求事務(wù)環(huán)境
         */
    }
}

5. 陷阱四:訪問(wèn)權(quán)限限制

5.1 訪問(wèn)權(quán)限完整示例

@Service
@Slf4j
public class AccessControlService {
    
    /**
     * 錯(cuò)誤示例:非public方法使用事務(wù)注解
     */
    @Transactional
    void internalProcessV1() {  // ? package-private方法
        // 事務(wù)不會(huì)生效
        repository.updateData();
    }
    
    @Transactional
    protected void protectedProcessV1() {  // ? protected方法  
        // 事務(wù)不會(huì)生效
        repository.updateData();
    }
    
    @Transactional
    private void privateProcessV1() {  // ? private方法
        // 事務(wù)不會(huì)生效
        repository.updateData();
    }
    
    /**
     * 解決方案
     */
    
    /**
     * 方案1:正確的訪問(wèn)權(quán)限
     */
    @Transactional
    public void publicProcess() {  // ? public方法
        repository.updateData();
    }
    
    /**
     * 方案2:門面模式 + 內(nèi)部方法調(diào)用
     */
    public void complexBusinessProcess() {
        // 步驟1:非事務(wù)性預(yù)處理
        preProcess();
        
        // 步驟2:事務(wù)性核心處理
        transactionalCoreProcess();
        
        // 步驟3:非事務(wù)性后處理
        postProcess();
    }
    
    @Transactional
    public void transactionalCoreProcess() {
        // 核心業(yè)務(wù)邏輯
        step1();
        step2();
        step3();
    }
    
    // 內(nèi)部方法 - 不添加事務(wù)注解
    private void preProcess() {
        // 數(shù)據(jù)驗(yàn)證、參數(shù)校驗(yàn)等
    }
    
    private void step1() {
        // 步驟1邏輯
    }
    
    private void step2() {
        // 步驟2邏輯
    }
    
    private void step3() {
        // 步驟3邏輯
    }
    
    private void postProcess() {
        // 清理、通知等
    }
    
    /**
     * 方案3:使用AspectJ模式(需要額外配置)
     */
    @Configuration
    @EnableTransactionManagement(mode = AdviceMode.ASPECTJ)  // 使用AspectJ代理
    public class AspectJTransactionConfig {
        // AspectJ模式下,非public方法的事務(wù)注解也會(huì)生效
        // 但需要編譯時(shí)或加載時(shí)織入
    }
    
    @Transactional
    protected void aspectJProtectedProcess() {
        // 在AspectJ模式下,protected方法的事務(wù)會(huì)生效
        repository.updateData();
    }
}

6. 陷阱五:數(shù)據(jù)庫(kù)配置問(wèn)題

6.1 數(shù)據(jù)庫(kù)配置完整示例

@Service
@Slf4j
public class DatabaseConfigService {
    
    /**
     * 錯(cuò)誤示例:使用不支持事務(wù)的存儲(chǔ)引擎
     */
    @Entity
    @Table(name = "operation_logs")
    public class OperationLog {
        // 如果數(shù)據(jù)庫(kù)表使用MyISAM引擎,事務(wù)將失效
    }
    
    @Transactional
    public void batchInsertLogsV1(List<OperationLog> logs) {
        for (OperationLog log : logs) {
            logRepository.save(log);  // ? MyISAM不支持事務(wù)
        }
        // 即使發(fā)生異常,已插入的數(shù)據(jù)也不會(huì)回滾
    }
    
    /**
     * 解決方案
     */
    
    /**
     * 方案1:確保使用InnoDB引擎
     */
    @Entity
    @Table(name = "operation_logs", 
           options = "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4")
    public class OperationLog {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        
        private String content;
        
        @CreationTimestamp
        private LocalDateTime createTime;
    }
    
    /**
     * 方案2:數(shù)據(jù)庫(kù)表DDL驗(yàn)證
     */
    @Component
    public class TableEngineValidator {
        
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        @PostConstruct
        public void validateTableEngines() {
            String sql = "SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES " +
                        "WHERE TABLE_SCHEMA = DATABASE() AND ENGINE != 'InnoDB'";
            
            List<Map<String, Object>> results = jdbcTemplate.queryForList(sql);
            
            if (!results.isEmpty()) {
                log.warn("發(fā)現(xiàn)非InnoDB引擎的表: {}", results);
                // 可以拋出異?;蛴涗浘?
            }
        }
    }
    
    /**
     * 方案3:編程式事務(wù) + 手動(dòng)回滾補(bǔ)償
     */
    @Service
    public class CompensationService {
        
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        public void batchInsertWithCompensation(List<OperationLog> logs) {
            List<Long> insertedIds = new ArrayList<>();
            
            try {
                for (OperationLog log : logs) {
                    // 手動(dòng)插入并記錄ID
                    Long id = insertLogAndReturnId(log);
                    insertedIds.add(id);
                }
                
                // 業(yè)務(wù)驗(yàn)證
                validateBusinessRules(logs);
                
            } catch (Exception e) {
                // 手動(dòng)回滾:刪除已插入的記錄
                rollbackInsertedLogs(insertedIds);
                throw new BusinessException("批量插入失敗,已回滾", e);
            }
        }
        
        private Long insertLogAndReturnId(OperationLog log) {
            KeyHolder keyHolder = new GeneratedKeyHolder();
            
            jdbcTemplate.update(connection -> {
                PreparedStatement ps = connection.prepareStatement(
                    "INSERT INTO operation_logs (content) VALUES (?)", 
                    Statement.RETURN_GENERATED_KEYS
                );
                ps.setString(1, log.getContent());
                return ps;
            }, keyHolder);
            
            return keyHolder.getKey().longValue();
        }
        
        private void rollbackInsertedLogs(List<Long> ids) {
            if (!ids.isEmpty()) {
                String deleteSql = "DELETE FROM operation_logs WHERE id IN (" +
                    ids.stream().map(String::valueOf).collect(Collectors.joining(",")) + ")";
                jdbcTemplate.update(deleteSql);
            }
        }
    }
}

7. 陷阱六:連接池配置問(wèn)題

7.1 連接池配置完整示例

@Configuration
public class DataSourceConfig {
    
    /**
     * 錯(cuò)誤示例:自動(dòng)提交設(shè)置沖突
     */
    @Bean
    public DataSource wrongDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        
        // ? 連接池自動(dòng)提交與事務(wù)管理沖突
        dataSource.setAutoCommit(true);
        
        return dataSource;
    }
    
    /**
     * 正確配置
     */
    @Bean
    @Primary
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        
        // ? 正確的連接池配置
        dataSource.setAutoCommit(false);  // 讓Spring管理事務(wù)提交
        dataSource.setConnectionTimeout(30000);
        dataSource.setIdleTimeout(600000);
        dataSource.setMaxLifetime(1800000);
        dataSource.setMaximumPoolSize(20);
        dataSource.setMinimumIdle(5);
        
        // 事務(wù)相關(guān)配置
        dataSource.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
        dataSource.setLeakDetectionThreshold(60000);
        
        return dataSource;
    }
    
    /**
     * 連接池監(jiān)控
     */
    @Component
    public class DataSourceMonitor {
        
        @Autowired
        private DataSource dataSource;
        
        @Scheduled(fixedRate = 30000)  // 每30秒監(jiān)控一次
        public void monitorDataSource() {
            if (dataSource instanceof HikariDataSource) {
                HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
                HikariPoolMXBean pool = hikariDataSource.getHikariPoolMXBean();
                
                log.info("連接池狀態(tài): 活躍={}, 空閑={}, 等待={}, 總數(shù)={}", 
                        pool.getActiveConnections(),
                        pool.getIdleConnections(),
                        pool.getThreadsAwaitingConnection(),
                        pool.getTotalConnections());
                
                // 檢查連接泄漏
                if (pool.getActiveConnections() > 15) {
                    log.warn("活躍連接數(shù)過(guò)高,可能存在連接泄漏");
                }
            }
        }
    }
}

8. 陷阱七:多數(shù)據(jù)源事務(wù)混淆

8.1 多數(shù)據(jù)源完整配置

@Configuration
public class MultiDataSourceConfig {
    
    /**
     * 主數(shù)據(jù)源
     */
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }
    
    /**
     * 從數(shù)據(jù)源
     */
    @Bean
    @ConfigurationProperties("spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }
    
    /**
     * 主數(shù)據(jù)源事務(wù)管理器
     */
    @Bean
    @Primary
    public PlatformTransactionManager primaryTransactionManager() {
        return new DataSourceTransactionManager(primaryDataSource());
    }
    
    /**
     * 從數(shù)據(jù)源事務(wù)管理器
     */
    @Bean
    public PlatformTransactionManager secondaryTransactionManager() {
        return new DataSourceTransactionManager(secondaryDataSource());
    }
    
    /**
     * JPA實(shí)體管理器工廠
     */
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource())
                .packages("com.example.primary.entity")
                .persistenceUnit("primary")
                .build();
    }
    
    @Bean
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource())
                .packages("com.example.secondary.entity")
                .persistenceUnit("secondary")
                .build();
    }
}

/**
 * 多數(shù)據(jù)源服務(wù)示例
 */
@Service
@Slf4j
public class MultiDataSourceService {
    
    @Autowired
    @Qualifier("primaryTransactionManager")
    private PlatformTransactionManager primaryTxManager;
    
    @Autowired
    @Qualifier("secondaryTransactionManager") 
    private PlatformTransactionManager secondaryTxManager;
    
    @Autowired
    private PrimaryRepository primaryRepository;
    
    @Autowired
    private SecondaryRepository secondaryRepository;
    
    /**
     * 錯(cuò)誤示例:錯(cuò)誤的事務(wù)管理器使用
     */
    @Transactional  // ? 使用默認(rèn)事務(wù)管理器,只能管理主數(shù)據(jù)源
    public void crossDataSourceOperationV1(CrossDataRequest request) {
        // 操作主數(shù)據(jù)源
        primaryRepository.save(request.getPrimaryData());
        
        // 操作從數(shù)據(jù)源 - 不在事務(wù)管理中!
        secondaryRepository.save(request.getSecondaryData());
        
        // 如果這里發(fā)生異常,主數(shù)據(jù)源會(huì)回滾,但從數(shù)據(jù)源不會(huì)
    }
    
    /**
     * 解決方案1:分別使用不同的事務(wù)管理器
     */
    public void crossDataSourceOperationV2(CrossDataRequest request) {
        // 主數(shù)據(jù)源操作
        primaryTxManager.execute(status -> {
            primaryRepository.save(request.getPrimaryData());
            return null;
        });
        
        // 從數(shù)據(jù)源操作  
        secondaryTxManager.execute(status -> {
            secondaryRepository.save(request.getSecondaryData());
            return null;
        });
        
        // 每個(gè)操作在獨(dú)立事務(wù)中,但無(wú)法保證原子性
    }
    
    /**
     * 解決方案2:使用分布式事務(wù)(如Atomikos)
     */
    @Configuration
    @EnableTransactionManagement
    public static class JtaTransactionConfig {
        
        @Bean
        public JtaTransactionManager transactionManager() {
            UserTransactionManager userTransactionManager = new UserTransactionManager();
            UserTransaction userTransaction = new UserTransactionImp();
            return new JtaTransactionManager(userTransaction, userTransactionManager);
        }
    }
    
    @Transactional  // 使用JTA事務(wù)管理器
    public void crossDataSourceOperationV3(CrossDataRequest request) {
        // 在分布式事務(wù)中,兩個(gè)數(shù)據(jù)源的操作會(huì)一起提交或回滾
        primaryRepository.save(request.getPrimaryData());
        secondaryRepository.save(request.getSecondaryData());
    }
    
    /**
     * 解決方案3:最終一致性模式
     */
    public void crossDataSourceOperationV4(CrossDataRequest request) {
        // 步驟1:主數(shù)據(jù)源操作
        Long primaryId = savePrimaryData(request.getPrimaryData());
        
        try {
            // 步驟2:從數(shù)據(jù)源操作
            saveSecondaryData(request.getSecondaryData(), primaryId);
            
            // 步驟3:標(biāo)記主數(shù)據(jù)完成
            markPrimaryDataCompleted(primaryId);
            
        } catch (Exception e) {
            // 步驟4:補(bǔ)償操作
            compensatePrimaryData(primaryId);
            throw new BusinessException("跨數(shù)據(jù)源操作失敗", e);
        }
    }
    
    @Transactional("primaryTransactionManager")
    public Long savePrimaryData(PrimaryData data) {
        PrimaryData saved = primaryRepository.save(data);
        return saved.getId();
    }
    
    @Transactional("secondaryTransactionManager")
    public void saveSecondaryData(SecondaryData data, Long primaryId) {
        data.setPrimaryId(primaryId);
        secondaryRepository.save(data);
    }
    
    @Transactional("primaryTransactionManager")
    public void markPrimaryDataCompleted(Long primaryId) {
        primaryRepository.updateStatus(primaryId, "COMPLETED");
    }
    
    @Transactional("primaryTransactionManager")
    public void compensatePrimaryData(Long primaryId) {
        primaryRepository.updateStatus(primaryId, "FAILED");
        // 可以記錄補(bǔ)償日志等
    }
}

9. 陷阱八:異步執(zhí)行事務(wù)丟失

9.1 異步事務(wù)完整示例

@Service
@Slf4j
@EnableAsync
public class AsyncTransactionService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private EmailService emailService;
    
    @Autowired
    private AsyncTransactionService self;
    
    /**
     * 錯(cuò)誤示例:異步方法中的事務(wù)注解
     */
    @Transactional
    @Async
    public void asyncProcessOrderV1(Order order) {
        // ? 異步方法中的事務(wù)注解通常不會(huì)按預(yù)期工作
        orderRepository.updateStatus(order.getId(), "PROCESSING");
        
        // 復(fù)雜的業(yè)務(wù)處理
        processComplexBusiness(order);
        
        orderRepository.updateStatus(order.getId(), "COMPLETED");
        // 事務(wù)上下文可能丟失,回滾機(jī)制不可靠
    }
    
    /**
     * 解決方案1:同步處理核心事務(wù),異步處理非核心操作
     */
    @Transactional
    public void processOrderV2(Order order) {
        // 步驟1:同步處理核心業(yè)務(wù)(在事務(wù)中)
        orderRepository.updateStatus(order.getId(), "PROCESSING");
        processCoreBusiness(order);
        orderRepository.updateStatus(order.getId(), "COMPLETED");
        
        // 步驟2:異步處理非核心操作(不在事務(wù)中)
        self.asyncSendNotifications(order);
    }
    
    @Async
    public void asyncSendNotifications(Order order) {
        try {
            // 發(fā)送郵件通知
            emailService.sendOrderCompleteEmail(order);
            
            // 發(fā)送短信通知
            smsService.sendOrderCompleteSms(order);
            
            // 其他非核心操作
            logService.recordOperationLog(order);
            
        } catch (Exception e) {
            // 異步操作失敗不影響主流程
            log.error("異步通知發(fā)送失敗: {}", order.getId(), e);
        }
    }
    
    /**
     * 解決方案2:使用@TransactionalEventListener
     */
    @Transactional
    public void processOrderV3(Order order) {
        // 核心業(yè)務(wù)處理
        orderRepository.updateStatus(order.getId(), "PROCESSING");
        processCoreBusiness(order);
        orderRepository.updateStatus(order.getId(), "COMPLETED");
        
        // 發(fā)布事務(wù)事件
        applicationEventPublisher.publishEvent(new OrderCompletedEvent(this, order));
    }
    
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    @Async
    public void handleOrderCompletedEvent(OrderCompletedEvent event) {
        // 只有在主事務(wù)提交后才會(huì)執(zhí)行
        Order order = event.getOrder();
        
        try {
            emailService.sendOrderCompleteEmail(order);
            smsService.sendOrderCompleteSms(order);
        } catch (Exception e) {
            log.error("訂單完成后續(xù)處理失敗: {}", order.getId(), e);
        }
    }
    
    /**
     * 解決方案3:編程式事務(wù) + 異步執(zhí)行
     */
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    @Async
    public void asyncProcessWithProgrammaticTx(Order order) {
        // 在異步線程中創(chuàng)建新事務(wù)
        transactionTemplate.execute(status -> {
            try {
                orderRepository.updateStatus(order.getId(), "PROCESSING");
                processCoreBusiness(order);
                orderRepository.updateStatus(order.getId(), "COMPLETED");
                return null;
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });
    }
    
    /**
     * 異步配置
     */
    @Configuration
    @EnableAsync
    public static class AsyncConfig implements AsyncConfigurer {
        
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(10);
            executor.setMaxPoolSize(50);
            executor.setQueueCapacity(100);
            executor.setThreadNamePrefix("AsyncTx-");
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            executor.setWaitForTasksToCompleteOnShutdown(true);
            executor.setAwaitTerminationSeconds(60);
            executor.initialize();
            return executor;
        }
        
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return (ex, method, params) -> {
                log.error("異步方法執(zhí)行異常: {}.{}", method.getDeclaringClass().getName(), method.getName(), ex);
            };
        }
    }
}

10. 陷阱九:事務(wù)超時(shí)與只讀設(shè)置

10.1 超時(shí)與只讀配置完整示例

@Service
@Slf4j
public class TimeoutReadonlyService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private OrderRepository orderRepository;
    
    /**
     * 錯(cuò)誤示例:長(zhǎng)事務(wù)無(wú)超時(shí)設(shè)置
     */
    @Transactional
    public void generateComplexReportV1(ReportRequest request) {
        // 步驟1:查詢大量數(shù)據(jù)
        List<User> users = userRepository.findAllActiveUsers();  // 可能很慢
        
        // 步驟2:復(fù)雜計(jì)算
        processComplexCalculation(users);  // 可能很慢
        
        // 步驟3:生成報(bào)告
        generateReportFile(users);  // 可能很慢
        
        // ? 沒(méi)有超時(shí)設(shè)置,可能長(zhǎng)時(shí)間占用數(shù)據(jù)庫(kù)連接
    }
    
    /**
     * 錯(cuò)誤示例:寫操作使用只讀事務(wù)
     */
    @Transactional(readOnly = true)  // ? 只讀事務(wù)
    public void updateUserStatisticsV1() {
        // 嘗試在只讀事務(wù)中執(zhí)行寫操作
        userRepository.updateStatistics();  // 可能失敗或行為異常
    }
    
    /**
     * 正確配置示例
     */
    
    /**
     * 方案1:合理設(shè)置超時(shí)時(shí)間
     */
    @Transactional(timeout = 30)  // ? 30秒超時(shí)
    public void generateComplexReportV2(ReportRequest request) {
        try {
            List<User> users = userRepository.findAllActiveUsers();
            processComplexCalculation(users);
            generateReportFile(users);
            
        } catch (TransactionTimedOutException e) {
            log.error("報(bào)告生成超時(shí): {}", request, e);
            throw new BusinessException("報(bào)告生成超時(shí),請(qǐng)重試");
        }
    }
    
    /**
     * 方案2:只讀事務(wù)用于查詢操作
     */
    @Transactional(readOnly = true, timeout = 10)
    public List<UserReport> getUserReports() {
        // 純查詢操作,使用只讀事務(wù)
        return userRepository.generateUserReports();
    }
    
    /**
     * 方案3:拆分長(zhǎng)事務(wù)
     */
    public void generateComplexReportV3(ReportRequest request) {
        // 步驟1:快速查詢必要數(shù)據(jù)
        List<Long> userIds = userRepository.findActiveUserIds();
        
        // 步驟2:分批處理
        Lists.partition(userIds, 1000).forEach(batch -> {
            processUserBatch(batch, request);
        });
    }
    
    @Transactional(timeout = 10)
    public void processUserBatch(List<Long> userIds, ReportRequest request) {
        List<User> users = userRepository.findByIdIn(userIds);
        processBatchCalculation(users);
        // 每個(gè)批次在獨(dú)立短事務(wù)中處理
    }
    
    /**
     * 方案4:動(dòng)態(tài)超時(shí)配置
     */
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public void processWithDynamicTimeout(boolean isComplex) {
        int timeout = isComplex ? 60 : 10;
        
        TransactionTemplate dynamicTemplate = new TransactionTemplate(
            transactionTemplate.getTransactionManager()
        );
        dynamicTemplate.setTimeout(timeout);
        
        dynamicTemplate.execute(status -> {
            // 業(yè)務(wù)邏輯
            return null;
        });
    }
    
    /**
     * 事務(wù)監(jiān)控和診斷
     */
    @Component
    @Aspect
    @Slf4j
    public class TransactionMonitorAspect {
        
        private final ThreadLocal<Long> startTime = new ThreadLocal<>();
        
        @Around("@annotation(transactional)")
        public Object monitorTransaction(ProceedingJoinPoint joinPoint, 
                                       Transactional transactional) throws Throwable {
            startTime.set(System.currentTimeMillis());
            
            String methodName = joinPoint.getSignature().toShortString();
            int timeout = transactional.timeout();
            
            log.info("事務(wù)開(kāi)始: {}, 超時(shí)時(shí)間: {}秒", methodName, timeout);
            
            try {
                Object result = joinPoint.proceed();
                long duration = System.currentTimeMillis() - startTime.get();
                
                if (duration > timeout * 1000L) {
                    log.warn("事務(wù)執(zhí)行時(shí)間接近超時(shí): {}ms, 方法: {}", duration, methodName);
                }
                
                return result;
                
            } catch (TransactionTimedOutException e) {
                log.error("事務(wù)超時(shí): {}, 配置超時(shí): {}秒", methodName, timeout, e);
                throw e;
            } finally {
                startTime.remove();
            }
        }
    }
}

11. 完整的事務(wù)測(cè)試方案

11.1 事務(wù)測(cè)試完整示例

@SpringBootTest
@TestPropertySource(properties = {
    "spring.datasource.url=jdbc:h2:mem:testdb",
    "spring.jpa.hibernate.ddl-auto=create-drop"
})
@Slf4j
class TransactionalTest {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Test
    void testTransactionRollbackOnException() {
        // 準(zhǔn)備測(cè)試數(shù)據(jù)
        OrderCreateRequest request = createTestRequest();
        request.setAmount(BigDecimal.ZERO);  // 觸發(fā)異常
        
        // 執(zhí)行測(cè)試
        assertThrows(BusinessException.class, () -> {
            orderService.createOrder(request);
        });
        
        // 驗(yàn)證事務(wù)回滾
        assertFalse(orderRepository.existsByOrderNo(request.getOrderNo()));
    }
    
    @Test
    void testTransactionCommitSuccess() {
        // 準(zhǔn)備測(cè)試數(shù)據(jù)
        OrderCreateRequest request = createTestRequest();
        request.setAmount(BigDecimal.TEN);
        
        // 執(zhí)行測(cè)試
        OrderCreateResult result = orderService.createOrder(request);
        
        // 驗(yàn)證事務(wù)提交
        assertTrue(result.isSuccess());
        assertTrue(orderRepository.existsByOrderNo(request.getOrderNo()));
    }
    
    @Test
    void testTransactionPropagation() {
        TransactionStatus status = transactionManager.getTransaction(
            new DefaultTransactionAttribute()
        );
        
        try {
            // 驗(yàn)證事務(wù)傳播
            boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
            assertTrue(isActive);
            
            String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
            assertNotNull(transactionName);
            
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
    
    @Test
    void testTransactionTimeout() {
        TransactionTemplate template = new TransactionTemplate(transactionManager);
        template.setTimeout(1);  // 1秒超時(shí)
        
        assertThrows(TransactionTimedOutException.class, () -> {
            template.execute(status -> {
                // 模擬長(zhǎng)時(shí)間操作
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return null;
            });
        });
    }
    
    /**
     * 事務(wù)測(cè)試配置
     */
    @TestConfiguration
    static class TestConfig {
        
        @Bean
        public DataSource dataSource() {
            return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .setName("testdb")
                .build();
        }
        
        @Bean
        public PlatformTransactionManager transactionManager(DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }
    
    private OrderCreateRequest createTestRequest() {
        OrderCreateRequest request = new OrderCreateRequest();
        request.setOrderNo("TEST_" + System.currentTimeMillis());
        request.setAmount(BigDecimal.valueOf(100));
        request.setUserId(1L);
        // 設(shè)置其他必要字段
        return request;
    }
}

12. 事務(wù)監(jiān)控與運(yùn)維

12.1 完整的事務(wù)監(jiān)控方案

@Component
@Slf4j
public class TransactionMonitor {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    private final Counter transactionCounter;
    private final Timer transactionTimer;
    private final Counter rollbackCounter;
    
    public TransactionMonitor(MeterRegistry meterRegistry) {
        this.transactionCounter = meterRegistry.counter("transaction.total");
        this.transactionTimer = meterRegistry.timer("transaction.duration");
        this.rollbackCounter = meterRegistry.counter("transaction.rollback");
    }
    
    @EventListener
    public void monitorTransactionEvent(ApplicationEvent event) {
        if (event instanceof TransactionCompletedEvent) {
            transactionCounter.increment();
        }
    }
    
    /**
     * 事務(wù)健康檢查
     */
    @Component
    public class TransactionHealthIndicator implements HealthIndicator {
        
        @Autowired
        private DataSource dataSource;
        
        @Override
        public Health health() {
            try {
                if (dataSource instanceof HikariDataSource) {
                    HikariDataSource hikari = (HikariDataSource) dataSource;
                    HikariPoolMXBean pool = hikari.getHikariPoolMXBean();
                    
                    int activeConnections = pool.getActiveConnections();
                    int maxPoolSize = hikari.getMaximumPoolSize();
                    
                    Health.Builder status = activeConnections > maxPoolSize * 0.8 ? 
                        Health.down() : Health.up();
                    
                    return status
                        .withDetail("activeConnections", activeConnections)
                        .withDetail("idleConnections", pool.getIdleConnections())
                        .withDetail("totalConnections", pool.getTotalConnections())
                        .withDetail("threadsAwaiting", pool.getThreadsAwaitingConnection())
                        .build();
                }
                
                return Health.unknown().build();
            } catch (Exception e) {
                return Health.down(e).build();
            }
        }
    }
    
    /**
     * 長(zhǎng)事務(wù)檢測(cè)和告警
     */
    @Component
    public class LongTransactionDetector {
        
        private final Map<String, Long> transactionStartTimes = new ConcurrentHashMap<>();
        
        @Autowired
        private PlatformTransactionManager transactionManager;
        
        @Scheduled(fixedRate = 30000)  // 每30秒檢查一次
        public void detectLongTransactions() {
            long currentTime = System.currentTimeMillis();
            long threshold = 30000;  // 30秒閾值
            
            transactionStartTimes.entrySet().removeIf(entry -> {
                long duration = currentTime - entry.getValue();
                
                if (duration > threshold) {
                    log.warn("發(fā)現(xiàn)長(zhǎng)事務(wù): {}, 持續(xù)時(shí)間: {}ms", entry.getKey(), duration);
                    // 發(fā)送告警
                    alertLongTransaction(entry.getKey(), duration);
                    return true;
                }
                
                return false;
            });
        }
        
        public void recordTransactionStart(String transactionId) {
            transactionStartTimes.put(transactionId, System.currentTimeMillis());
        }
        
        public void recordTransactionEnd(String transactionId) {
            transactionStartTimes.remove(transactionId);
        }
        
        private void alertLongTransaction(String transactionId, long duration) {
            // 發(fā)送郵件、短信、釘釘?shù)雀婢?
            log.error("長(zhǎng)事務(wù)告警: {}, 持續(xù)時(shí)間: {}ms", transactionId, duration);
        }
    }
}

13. 總結(jié):事務(wù)管理最佳實(shí)踐

13.1 事務(wù)設(shè)計(jì)原則

/**
 * 事務(wù)管理最佳實(shí)踐總結(jié)
 */
public class TransactionBestPractices {
    
    /*
     * 1. 事務(wù)邊界原則
     *    - 事務(wù)應(yīng)該圍繞業(yè)務(wù)用例,而不是技術(shù)細(xì)節(jié)
     *    - 保持事務(wù)簡(jiǎn)短,避免長(zhǎng)事務(wù)
     *    - 在服務(wù)層管理事務(wù),而不是在DAO層
     */
    
    /*
     * 2. 異常處理原則  
     *    - 明確指定回滾異常類型
     *    - 避免在事務(wù)中捕獲所有異常
     *    - 將檢查異常轉(zhuǎn)換為非檢查異常
     */
    
    /*
     * 3. 性能優(yōu)化原則
     *    - 查詢操作使用只讀事務(wù)
     *    - 合理設(shè)置事務(wù)超時(shí)時(shí)間
     *    - 避免在事務(wù)中進(jìn)行遠(yuǎn)程調(diào)用和IO操作
     */
    
    /*
     * 4. 復(fù)雜度控制原則
     *    - 避免嵌套事務(wù)的過(guò)度使用
     *    - 明確事務(wù)傳播行為
     *    - 使用編程式事務(wù)處理復(fù)雜場(chǎng)景
     */
    
    /*
     * 5. 監(jiān)控運(yùn)維原則
     *    - 監(jiān)控事務(wù)執(zhí)行時(shí)間和成功率
     *    - 設(shè)置長(zhǎng)事務(wù)告警
     *    - 定期審查事務(wù)配置
     */
}

13.2 事務(wù)配置檢查清單

@Component
public class TransactionChecklist {
    
    /**
     * 事務(wù)配置驗(yàn)證
     */
    public void validateTransactionConfiguration() {
        checkPublicMethods();
        checkExceptionConfiguration();
        checkTimeoutSettings();
        checkDataSourceConfiguration();
        checkAopConfiguration();
    }
    
    private void checkPublicMethods() {
        // 驗(yàn)證所有@Transactional方法都是public
    }
    
    private void checkExceptionConfiguration() {
        // 驗(yàn)證回滾異常配置
    }
    
    private void checkTimeoutSettings() {
        // 驗(yàn)證超時(shí)時(shí)間配置
    }
    
    private void checkDataSourceConfiguration() {
        // 驗(yàn)證數(shù)據(jù)源和連接池配置
    }
    
    private void checkAopConfiguration() {
        // 驗(yàn)證AOP代理配置
    }
}

通過(guò)以上完整的示例和解決方案,相信你已經(jīng)對(duì)Spring事務(wù)失效的各種場(chǎng)景有了全面的理解。記住,事務(wù)管理不僅是技術(shù)問(wèn)題,更是架構(gòu)設(shè)計(jì)和業(yè)務(wù)理解的體現(xiàn)。

以上就是Spring事務(wù)失效的十大陷阱與終極解決方案的詳細(xì)內(nèi)容,更多關(guān)于Spring事務(wù)失效陷阱與解決的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • RocketMQ事務(wù)消息使用與原理詳解

    RocketMQ事務(wù)消息使用與原理詳解

    這篇文章主要為大家介紹了RocketMQ事務(wù)消息的實(shí)現(xiàn)原理,在分布式事務(wù)解決方案中,事務(wù)消息也是一個(gè)不錯(cuò)的解決方案,本篇文章將圍繞RocketMQ的事務(wù)消息實(shí)現(xiàn)展開(kāi)描述,需要的朋友可以參考下
    2023-07-07
  • IISExpress?配置允許外部訪問(wèn)詳細(xì)介紹

    IISExpress?配置允許外部訪問(wèn)詳細(xì)介紹

    這篇文章主要介紹了?IISExpress?配置允許外部訪問(wèn)詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • Java并發(fā)編程之Condition源碼分析(推薦)

    Java并發(fā)編程之Condition源碼分析(推薦)

    這篇文章主要介紹了Java并發(fā)編程之Condition源碼分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 從基礎(chǔ)學(xué)java--數(shù)組

    從基礎(chǔ)學(xué)java--數(shù)組

    數(shù)組是相同類型數(shù)據(jù)的有序集合數(shù)組描述的是相同類型的若干個(gè)數(shù)據(jù),按照一定的先后次序排列組合而成。其中,每一個(gè)數(shù)據(jù)稱作一個(gè)數(shù)組元素,每個(gè)數(shù)組元素可以通過(guò)一個(gè)下標(biāo)來(lái)訪問(wèn)它們數(shù)組的聲明創(chuàng)建
    2021-09-09
  • 解析java中的error該不該捕獲

    解析java中的error該不該捕獲

    這篇文章主要介紹了java中的error該不該捕獲,需要的朋友可以參考下
    2014-02-02
  • 淺談java常量池

    淺談java常量池

    下面小編就為大家?guī)?lái)一篇淺談java常量池。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-06-06
  • macOS中搭建Java8開(kāi)發(fā)環(huán)境(基于Intel?x86?64-bit)

    macOS中搭建Java8開(kāi)發(fā)環(huán)境(基于Intel?x86?64-bit)

    這篇文章主要介紹了macOS中搭建Java8開(kāi)發(fā)環(huán)境(基于Intel?x86?64-bit)?的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 解決Spring Security的權(quán)限配置不生效問(wèn)題

    解決Spring Security的權(quán)限配置不生效問(wèn)題

    這篇文章主要介紹了解決Spring Security的權(quán)限配置不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java 部署滾動(dòng)更新的方法(K8s RollingUpdate 策略)

    Java 部署滾動(dòng)更新的方法(K8s RollingUpdate 策略)

    本文詳細(xì)介紹了在Kubernetes中如何對(duì)Java應(yīng)用實(shí)施滾動(dòng)更新,涵蓋原理、配置、最佳實(shí)踐、故障處理以及完整的代碼與部署示例,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • Spring Boot 發(fā)送郵件功能案例分析

    Spring Boot 發(fā)送郵件功能案例分析

    這篇文章主要介紹了 Spring Boot 發(fā)送郵件功能,本文通過(guò)代碼結(jié)合案例分析給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2017-11-11

最新評(píng)論

枞阳县| 汨罗市| 屏东市| 马尔康县| 大理市| 广元市| 安阳市| 全州县| 金塔县| 内江市| 凤庆县| 西青区| 思南县| 辛集市| 清新县| 桐柏县| 都匀市| 镇康县| 章丘市| 巴东县| 东港市| 鸡泽县| 台南市| 新兴县| 高雄县| 中牟县| 邳州市| 长宁县| 宁化县| 丰顺县| 银川市| 宁陕县| 全州县| 商河县| 灵山县| 临西县| 丰城市| 祥云县| 临城县| 如东县| 锡林浩特市|