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

淺析SpringBoot中如何啟用MongoDB事務

 更新時間:2025年05月12日 10:09:41   作者:冰糖心書房  
這篇文章主要為大家詳細介紹了SpringBoot中如何啟用MongoDB事務,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

前言

在 Spring Boot 中啟用和使用 MongoDB 事務主要依賴于以下幾個方面:

1.MongoDB 服務器和部署模式:

  • MongoDB 版本 4.0 或更高版本才支持副本集 (Replica Set) 上的多文檔 ACID 事務。
  • MongoDB 版本 4.2 或更高版本才支持分片集群 (Sharded Cluster) 上的多文檔 ACID 事務。
  • Standalone (單節(jié)點) 模式不支持多文檔事務。 MongoDB 實例必須是副本集或分片集群的一部分。

2.Spring Boot 和 Spring Data MongoDB 版本:

  • 確保使用的 Spring Boot 版本(以及它所管理的 Spring Data MongoDB 版本)支持 MongoDB 事務。較新的 Spring Boot 版本(2.1.x 及以后)都提供了良好的支持。
  • spring-boot-starter-data-mongodb 依賴是必需的。

3.配置 MongoTransactionManager:

Spring Boot 會在檢測到合適的條件時(例如,連接 URI 指向一個副本集)自動配置 MongoTransactionManager。

4.使用 @Transactional 注解:

這是在 Spring 中管理事務的標準方式。

下面是如何在 Spring Boot 中啟用和使用 MongoDB 事務:

步驟 1: 確保 MongoDB 環(huán)境支持事務

確認MongoDB 服務器版本(4.0+ for replica sets, 4.2+ for sharded clusters)。

確認MongoDB 是以副本集或分片集群模式運行。

步驟 2: 添加依賴

在你的 pom.xml (Maven) 或 build.gradle (Gradle) 文件中,確保有 Spring Data MongoDB 的 starter:

Maven (pom.xml):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

步驟 3: 配置數(shù)據(jù)庫連接 URI

在 application.properties 或 application.yml 中配置 MongoDB 連接 URI。關鍵是要包含 replicaSet 參數(shù)(如果你的 MongoDB 是副本集)。

application.properties:

spring.data.mongodb.uri=mongodb://localhost:27017,localhost:27018,localhost:27019/mydatabase?replicaSet=rs0
# 或者對于分片集群,連接到 mongos 實例
# spring.data.mongodb.uri=mongodb://mongos1:27017,mongos2:27017/mydatabase

localhost:27017,localhost:27018,localhost:27019:副本集成員地址。

mydatabase:數(shù)據(jù)庫名稱。

replicaSet=rs0:副本集名稱。這個參數(shù)對于 Spring Boot 自動配置 MongoTransactionManager 非常重要。

步驟 4: 啟用事務管理器

a) 自動配置 (推薦)

如果 spring.data.mongodb.uri 正確配置了 replicaSet 參數(shù)(或者連接的是分片集群的 mongos),Spring Boot 通常會自動為你配置一個MongoTransactionManager bean。不需要額外做配置。

b) 手動配置 (如果自動配置不生效或需要自定義)

如果需要手動配置,可以在配置類中創(chuàng)建一個 MongoTransactionManager bean:

import com.mongodb.client.MongoClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.MongoTransactionManager;
import org.springframework.data.mongodb.core.MongoTemplate; // 僅為示例,非必需

@Configuration
public class MongoConfig {

    // Spring Boot 會自動配置 MongoDatabaseFactory
    // 你只需要注入它來創(chuàng)建 MongoTransactionManager
    @Bean
    MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }

    // 可選: 如果你也想配置一個 MongoTemplate bean
    // @Bean
    // public MongoTemplate mongoTemplate(MongoDatabaseFactory dbFactory, MongoClient mongoClient) {
    //     return new MongoTemplate(mongoClient, dbFactory.getMongoDatabase().getName());
    // }
}

注意: 通常情況下,如果你的 URI 配置正確,Spring Boot 的自動配置就足夠了,你不需要手動創(chuàng)建這個 bean。

步驟 5: 在 Service 層使用 @Transactional

現(xiàn)在可以在Service 方法上使用 Spring 的 @Transactional 注解來聲明事務。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; // Spring的事務注解
import com.mongodb.MongoException; // 更通用的MongoDB異常
import com.mongodb.MongoTransactionException; // 事務特定異常

@Service
public class AccountService {

    @Autowired
    private AccountRepository accountRepository; // 假設你有一個 AccountRepository

    @Autowired
    private AuditLogRepository auditLogRepository; // 假設你有一個 AuditLogRepository


    /**
     * 示例:在一個事務中轉賬并記錄日志
     * 如果任何一步失敗,整個操作將回滾
     */
    @Transactional // 關鍵注解
    public void transferMoney(String fromAccountId, String toAccountId, double amount) {
        try {
            Account fromAccount = accountRepository.findById(fromAccountId)
                    .orElseThrow(() -> new RuntimeException("Source account not found"));
            Account toAccount = accountRepository.findById(toAccountId)
                    .orElseThrow(() -> new RuntimeException("Destination account not found"));

            if (fromAccount.getBalance() < amount) {
                throw new RuntimeException("Insufficient funds");
            }

            fromAccount.setBalance(fromAccount.getBalance() - amount);
            toAccount.setBalance(toAccount.getBalance() + amount);

            accountRepository.save(fromAccount);

            // 模擬一個可能發(fā)生的錯誤,以測試回滾
            // if (true) {
            //     throw new RuntimeException("Simulated error during transfer!");
            // }

            accountRepository.save(toAccount);

            // 記錄審計日志
            AuditLog log = new AuditLog("Transfer of " + amount + " from " + fromAccountId + " to " + toAccountId);
            auditLogRepository.save(log);

            System.out.println("Transfer successful and logged!");

        } catch (RuntimeException e) {
            // @Transactional 會在 RuntimeException 拋出時自動回滾
            // 你可以在這里記錄錯誤,但不需要手動回滾
            System.err.println("Transfer failed: " + e.getMessage());
            throw e; // 重新拋出,以便 Spring 能夠捕獲并回滾事務
        }
    }

    /**
     * 示例:只讀事務
     * 對于只需要讀取數(shù)據(jù)的操作,可以標記為只讀,這可能有一些性能優(yōu)化。
     */
    @Transactional(readOnly = true)
    public Account getAccountDetails(String accountId) {
        return accountRepository.findById(accountId).orElse(null);
    }

    // 假設的實體和倉庫
    // Account.java, AuditLog.java
    // AccountRepository.java extends MongoRepository<Account, String>
    // AuditLogRepository.java extends MongoRepository<AuditLog, String>
}

工作原理:

  • 當調用被 @Transactional 注解的方法時,Spring 會啟動一個 MongoDB 事務(通過 MongoTransactionManager)。
  • 方法內的所有數(shù)據(jù)庫操作(例如 repository.save())都會在這個事務的上下文中執(zhí)行。
  • 如果方法成功完成(沒有拋出未被捕獲的 RuntimeException 或 Error),事務將被提交。
  • 如果方法拋出任何未被捕獲的 RuntimeException 或 Error(默認行為),事務將被回滾。受檢異常(Checked Exceptions)默認不會觸發(fā)回滾,除非通過 @Transactional(rollbackFor = SpecificCheckedException.class) 特別指定。

步驟 6: 異常處理和重試 (重要!)

MongoDB 事務可能會因為寫沖突 (write conflicts) 而中止。當兩個并發(fā)事務嘗試修改同一個文檔時,就會發(fā)生這種情況。MongoDB 會中止其中一個事務,并拋出 MongoTransactionException (通常是其子類,如 MongoWriteConflictException)。

在應用程序中必須捕獲這些異常并重試整個事務。

// 在調用方或者一個更高層次的Service
@Service
public class TransactionalCallerService {

    @Autowired
    private AccountService accountService;

    private static final int MAX_RETRIES = 3;

    public void performTransferWithRetry(String from, String to, double amount) {
        int retries = 0;
        boolean success = false;
        while (retries < MAX_RETRIES && !success) {
            try {
                accountService.transferMoney(from, to, amount);
                success = true; // 如果沒有異常,標記成功
            } catch (MongoTransactionException e) { // 捕獲事務相關的異常,特別是寫沖突
                retries++;
                System.err.println("Transaction failed due to conflict, retrying (" + retries + "/" + MAX_RETRIES + "): " + e.getMessage());
                if (retries >= MAX_RETRIES) {
                    System.err.println("Max retries reached. Transfer aborted.");
                    throw e; // 或者拋出一個自定義的業(yè)務異常
                }
                // 可以考慮在此處添加短暫的延遲
                try {
                    Thread.sleep(100 * retries); // 簡單的指數(shù)退避
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("Retry interrupted", ie);
                }
            } catch (RuntimeException e) { // 捕獲其他業(yè)務邏輯異常
                System.err.println("Transfer failed due to business error: " + e.getMessage());
                throw e; // 這些通常不需要重試
            }
        }
    }
}

總結關鍵點:

  • MongoDB 環(huán)境: 確保是副本集 (4.0+) 或分片集群 (4.2+)。
  • URI 配置: 在 spring.data.mongodb.uri 中正確設置 replicaSet 參數(shù)。
  • MongoTransactionManager: 通常由 Spring Boot 自動配置。
  • @Transactional: 在 Service 方法上使用。
  • 異常處理: 必須處理 MongoTransactionException 并實現(xiàn)重試邏輯以應對寫沖突。
  • 事務范圍: 盡量保持事務簡短,避免長時間運行的事務。
  • 非事務操作: 某些 MongoDB 操作(如創(chuàng)建集合、創(chuàng)建索引)不在事務內執(zhí)行或在事務內有特定行為。

通過這些步驟,我們就可以在 Spring Boot 應用程序中有效的使用 MongoDB 的多文檔 ACID 事務了。

到此這篇關于淺析SpringBoot中如何啟用MongoDB事務的文章就介紹到這了,更多相關SpringBoot啟用MongoDB事務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 一篇文章弄懂Java8中的時間處理

    一篇文章弄懂Java8中的時間處理

    Java8以前Java處理日期、日歷和時間的方式一直為社區(qū)所詬病,將 java.util.Date設定為可變類型,以及SimpleDateFormat的非線程安全使其應用非常受限,下面這篇文章主要給大家介紹了關于Java8中時間處理的相關資料,需要的朋友可以參考下
    2022-01-01
  • 如何解決springboot數(shù)據(jù)庫查詢時出現(xiàn)的時區(qū)差異問題

    如何解決springboot數(shù)據(jù)庫查詢時出現(xiàn)的時區(qū)差異問題

    這篇文章主要介紹了如何解決springboot數(shù)據(jù)庫查詢時出現(xiàn)的時區(qū)差異問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 講解Java設計模式編程中的建造者模式與原型模式

    講解Java設計模式編程中的建造者模式與原型模式

    這篇文章主要介紹了Java設計模式編程中的建造者模式與原型模式,設計模式有利于團隊開發(fā)過程中的代碼維護,需要的朋友可以參考下
    2016-02-02
  • mybatis 根據(jù)id批量刪除的實現(xiàn)操作

    mybatis 根據(jù)id批量刪除的實現(xiàn)操作

    這篇文章主要介紹了mybatis 根據(jù)id批量刪除的實現(xiàn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 基于FLink實現(xiàn)實時安全檢測的示例代碼

    基于FLink實現(xiàn)實時安全檢測的示例代碼

    這篇文章主要為大家詳細介紹了如何基于FLink實現(xiàn)實時安全檢測的功能,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的可以了解一下
    2023-02-02
  • java發(fā)送http get請求的兩種方式

    java發(fā)送http get請求的兩種方式

    這篇文章主要為大家詳細介紹了java發(fā)送http get請求的兩種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java實現(xiàn)多對多網(wǎng)絡通訊的流程

    Java實現(xiàn)多對多網(wǎng)絡通訊的流程

    這篇文章主要介紹了Java實現(xiàn)多對多網(wǎng)絡通訊的流程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 教你一步到位部署運行MyBatis3源碼(保姆級)

    教你一步到位部署運行MyBatis3源碼(保姆級)

    一個框架的運行流程從最簡單的一個helloworld來看其源碼就能了解到框架的原理是什么,這篇文章主要給大家介紹了關于如何一步到位部署運行MyBatis3源碼的相關資料,需要的朋友可以參考下
    2022-06-06
  • Java開發(fā)之Spring連接數(shù)據(jù)庫方法實例分析

    Java開發(fā)之Spring連接數(shù)據(jù)庫方法實例分析

    這篇文章主要介紹了Java開發(fā)之Spring連接數(shù)據(jù)庫方法,以實例形式較為詳細的分析了Java Spring開發(fā)中針對數(shù)據(jù)庫的相關操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • Java設計模式之代理模式解析

    Java設計模式之代理模式解析

    這篇文章主要介紹了Java設計模式之代理模式解析,代理模式為一個對象提供一個替身,以控制對這個對象的訪問,即通過代理對象訪問目標對象,需要的朋友可以參考下
    2023-12-12

最新評論

新绛县| 盐亭县| 博乐市| 右玉县| 迁西县| 内黄县| 黔西| 遵义市| 台北县| 佛冈县| 突泉县| 普宁市| 育儿| 观塘区| 建瓯市| 桓台县| 福建省| 海盐县| 沈丘县| 固始县| 新源县| 武宣县| 平凉市| 康乐县| 县级市| 云南省| 广丰县| 萍乡市| 上犹县| 北辰区| 金堂县| 门头沟区| 淳安县| 呼图壁县| 龙川县| 济阳县| 云安县| 论坛| 利辛县| 新竹市| 巴林右旗|