欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析SpringBoot中如何啟用MongoDB事務(wù)

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

前言

在 Spring Boot 中啟用和使用 MongoDB 事務(wù)主要依賴(lài)于以下幾個(gè)方面:

1.MongoDB 服務(wù)器和部署模式:

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

2.Spring Boot 和 Spring Data MongoDB 版本:

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

3.配置 MongoTransactionManager:

Spring Boot 會(huì)在檢測(cè)到合適的條件時(shí)(例如,連接 URI 指向一個(gè)副本集)自動(dòng)配置 MongoTransactionManager。

4.使用 @Transactional 注解:

這是在 Spring 中管理事務(wù)的標(biāo)準(zhǔn)方式。

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

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

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

確認(rèn)MongoDB 是以副本集或分片集群模式運(yùn)行。

步驟 2: 添加依賴(lài)

在你的 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ù)庫(kù)連接 URI

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

application.properties:

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

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

mydatabase:數(shù)據(jù)庫(kù)名稱(chēng)。

replicaSet=rs0:副本集名稱(chēng)。這個(gè)參數(shù)對(duì)于 Spring Boot 自動(dòng)配置 MongoTransactionManager 非常重要。

步驟 4: 啟用事務(wù)管理器

a) 自動(dòng)配置 (推薦)

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

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

如果需要手動(dòng)配置,可以在配置類(lèi)中創(chuàng)建一個(gè) 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 會(huì)自動(dòng)配置 MongoDatabaseFactory
    // 你只需要注入它來(lái)創(chuàng)建 MongoTransactionManager
    @Bean
    MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }

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

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

步驟 5: 在 Service 層使用 @Transactional

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

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

@Service
public class AccountService {

    @Autowired
    private AccountRepository accountRepository; // 假設(shè)你有一個(gè) AccountRepository

    @Autowired
    private AuditLogRepository auditLogRepository; // 假設(shè)你有一個(gè) AuditLogRepository


    /**
     * 示例:在一個(gè)事務(wù)中轉(zhuǎn)賬并記錄日志
     * 如果任何一步失敗,整個(gè)操作將回滾
     */
    @Transactional // 關(guān)鍵注解
    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);

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

            accountRepository.save(toAccount);

            // 記錄審計(jì)日志
            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 會(huì)在 RuntimeException 拋出時(shí)自動(dòng)回滾
            // 你可以在這里記錄錯(cuò)誤,但不需要手動(dòng)回滾
            System.err.println("Transfer failed: " + e.getMessage());
            throw e; // 重新拋出,以便 Spring 能夠捕獲并回滾事務(wù)
        }
    }

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

    // 假設(shè)的實(shí)體和倉(cāng)庫(kù)
    // Account.java, AuditLog.java
    // AccountRepository.java extends MongoRepository<Account, String>
    // AuditLogRepository.java extends MongoRepository<AuditLog, String>
}

工作原理:

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

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

MongoDB 事務(wù)可能會(huì)因?yàn)閷?xiě)沖突 (write conflicts) 而中止。當(dāng)兩個(gè)并發(fā)事務(wù)嘗試修改同一個(gè)文檔時(shí),就會(huì)發(fā)生這種情況。MongoDB 會(huì)中止其中一個(gè)事務(wù),并拋出 MongoTransactionException (通常是其子類(lèi),如 MongoWriteConflictException)。

在應(yīng)用程序中必須捕獲這些異常并重試整個(gè)事務(wù)。

// 在調(diào)用方或者一個(gè)更高層次的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; // 如果沒(méi)有異常,標(biāo)記成功
            } catch (MongoTransactionException e) { // 捕獲事務(wù)相關(guān)的異常,特別是寫(xiě)沖突
                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; // 或者拋出一個(gè)自定義的業(yè)務(wù)異常
                }
                // 可以考慮在此處添加短暫的延遲
                try {
                    Thread.sleep(100 * retries); // 簡(jiǎn)單的指數(shù)退避
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("Retry interrupted", ie);
                }
            } catch (RuntimeException e) { // 捕獲其他業(yè)務(wù)邏輯異常
                System.err.println("Transfer failed due to business error: " + e.getMessage());
                throw e; // 這些通常不需要重試
            }
        }
    }
}

總結(jié)關(guān)鍵點(diǎn):

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

通過(guò)這些步驟,我們就可以在 Spring Boot 應(yīng)用程序中有效的使用 MongoDB 的多文檔 ACID 事務(wù)了。

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

相關(guān)文章

  • Java實(shí)現(xiàn)快速生成詞云圖的示例代碼

    Java實(shí)現(xiàn)快速生成詞云圖的示例代碼

    詞云(Word?Cloud),又稱(chēng)文字云、標(biāo)簽云(Tag?Cloud)、關(guān)鍵詞云(Keyword?Cloud),是對(duì)文本信息中一定數(shù)量的關(guān)鍵詞出現(xiàn)的頻率高低情況的一種可視化展現(xiàn)方式。本文將用Java代碼實(shí)現(xiàn)快速生成詞云圖,需要的可以參考一下
    2023-02-02
  • Java實(shí)現(xiàn)獲取控制臺(tái)輸出結(jié)果轉(zhuǎn)換為變量的詳細(xì)操作

    Java實(shí)現(xiàn)獲取控制臺(tái)輸出結(jié)果轉(zhuǎn)換為變量的詳細(xì)操作

    在Java編程中,有時(shí)需將控制臺(tái)的輸出捕獲為字符串,以便于后續(xù)的處理或測(cè)試,這種需求在日志記錄、單元測(cè)試或調(diào)試時(shí)尤為常見(jiàn),下面,將通過(guò)詳細(xì)步驟來(lái)介紹如何使用ByteArrayOutputStream和PrintStream來(lái)實(shí)現(xiàn)這一功能,需要的朋友可以參考下
    2024-06-06
  • intelij?idea?2023創(chuàng)建java?web項(xiàng)目的完整步驟

    intelij?idea?2023創(chuàng)建java?web項(xiàng)目的完整步驟

    這篇文章主要給大家介紹了關(guān)于intelij?idea?2023創(chuàng)建java?web項(xiàng)目的完整步驟,該教學(xué)主要針對(duì)各位剛剛接觸javaweb開(kāi)發(fā)的小伙伴,各位學(xué)習(xí)java的朋友也難免會(huì)經(jīng)歷這個(gè)階段,需要的朋友可以參考下
    2023-10-10
  • IntelliJ IDEA 2018 最新激活碼(截止到2018年1月30日)

    IntelliJ IDEA 2018 最新激活碼(截止到2018年1月30日)

    這篇文章主要介紹了IntelliJ IDEA 2018 最新激活碼(截止到2018年1月30日)的相關(guān)資料,需要的朋友可以參考下
    2018-01-01
  • SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(后端)

    SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(后端)

    這篇文章主要介紹了SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(后端),快速生成后端代碼、封裝結(jié)果集、增刪改查、模糊查找,畢設(shè)基礎(chǔ)框架,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • jar包中替換指定的class文件方法詳解

    jar包中替換指定的class文件方法詳解

    這篇文章主要為大家介紹了jar包中替換指定的class文件方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 責(zé)任鏈模式在spring security過(guò)濾器鏈中的應(yīng)用小結(jié)

    責(zé)任鏈模式在spring security過(guò)濾器鏈中的應(yīng)用小結(jié)

    責(zé)任鏈模式在SpringSecurity過(guò)濾器鏈中的應(yīng)用,通過(guò)一系列的過(guò)濾器按順序處理請(qǐng)求,每個(gè)過(guò)濾器負(fù)責(zé)特定的安全功能,實(shí)現(xiàn)靈活且可擴(kuò)展的請(qǐng)求處理機(jī)制,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Java+opencv3.2.0之scharr濾波器

    Java+opencv3.2.0之scharr濾波器

    這篇文章主要為大家詳細(xì)介紹了Java+opencv3.2.0之scharr濾波器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Java簡(jiǎn)單工廠模式詳細(xì)解釋

    Java簡(jiǎn)單工廠模式詳細(xì)解釋

    本文主要介紹了JAVA簡(jiǎn)單工廠模式(從現(xiàn)實(shí)生活角度理解代碼原理)的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2021-11-11
  • ElasticSearch如何設(shè)置某個(gè)字段不分詞淺析

    ElasticSearch如何設(shè)置某個(gè)字段不分詞淺析

    最近在學(xué)習(xí)ElasticSearch官方文檔過(guò)程中發(fā)現(xiàn)的某個(gè)問(wèn)題,記錄一下 希望能幫助到后面的朋友,下面這篇文章主要給大家介紹了關(guān)于ElasticSearch如何設(shè)置某個(gè)字段不分詞的相關(guān)資料,需要的朋友可以參考下
    2022-04-04

最新評(píng)論