MongoDB(81)事务的应用场景有哪些?

0 阅读3分钟

在实际应用中,事务的应用场景非常广泛,尤其是在确保数据一致性和可靠性方面。以下是一些常见的事务应用场景,并结合Java代码示例进行详细解释:

1. 资金转账

场景描述:在银行系统中,从一个账户转账到另一个账户时,需要确保资金从一个账户扣除的同时,另一个账户接收到相应的资金。如果任何一步失败,都需要回滚所有操作。

代码示例

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

public class BankTransferExample {

    public static void main(String[] args) {

        // 创建 MongoClient
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");

        // 获取数据库和集合
        MongoDatabase database = mongoClient.getDatabase("bankdb");
        MongoCollection<Document> accounts = database.getCollection("accounts");

        // 插入初始数据
        accounts.insertOne(new Document("account", "Alice").append("balance", 1000));
        accounts.insertOne(new Document("account", "Bob").append("balance", 500));

        // 开始会话
        ClientSession session = mongoClient.startSession();

        // 配置事务选项
        TransactionOptions txnOptions = TransactionOptions.builder()
                .readPreference(ReadPreference.primary())
                .readConcern(ReadConcern.LOCAL)
                .writeConcern(WriteConcern.MAJORITY)
                .build();

        try {
            // 开始事务
            session.startTransaction(txnOptions);

            // 执行转账操作
            Document aliceAccount = accounts.find(session, new Document("account", "Alice")).first();
            if (aliceAccount != null && aliceAccount.getInteger("balance") >= 100) {
                accounts.updateOne(session, new Document("account", "Alice"),
                        new Document("$inc", new Document("balance", -100)));
                accounts.updateOne(session, new Document("account", "Bob"),
                        new Document("$inc", new Document("balance", 100)));
            } else {
                throw new RuntimeException("Insufficient balance!");
            }

            // 提交事务
            session.commitTransaction();
            System.out.println("Transaction committed.");
        } catch (MongoException | RuntimeException e) {
            // 回滚事务
            session.abortTransaction();
            System.err.println("Transaction aborted due to: " + e.getMessage());
        } finally {
            session.close();
        }

        mongoClient.close();
    }
}

2. 订单处理

场景描述:在电子商务系统中,处理订单时需要确保订单信息和库存信息的一致性。例如,在创建订单的同时,需要减少相应商品的库存。

代码示例

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

public class OrderProcessingExample {

    public static void main(String[] args) {

        // 创建 MongoClient
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");

        // 获取数据库和集合
        MongoDatabase database = mongoClient.getDatabase("ecommercedb");
        MongoCollection<Document> orders = database.getCollection("orders");
        MongoCollection<Document> inventory = database.getCollection("inventory");

        // 插入初始数据
        inventory.insertOne(new Document("product", "Laptop").append("quantity", 50));

        // 开始会话
        ClientSession session = mongoClient.startSession();

        // 配置事务选项
        TransactionOptions txnOptions = TransactionOptions.builder()
                .readPreference(ReadPreference.primary())
                .readConcern(ReadConcern.LOCAL)
                .writeConcern(WriteConcern.MAJORITY)
                .build();

        try {
            // 开始事务
            session.startTransaction(txnOptions);

            // 执行订单处理操作
            Document product = inventory.find(session, new Document("product", "Laptop")).first();
            if (product != null && product.getInteger("quantity") >= 1) {
                orders.insertOne(session, new Document("orderID", "O1001").append("product", "Laptop").append("quantity", 1));
                inventory.updateOne(session, new Document("product", "Laptop"),
                        new Document("$inc", new Document("quantity", -1)));
            } else {
                throw new RuntimeException("Insufficient inventory!");
            }

            // 提交事务
            session.commitTransaction();
            System.out.println("Transaction committed.");
        } catch (MongoException | RuntimeException e) {
            // 回滚事务
            session.abortTransaction();
            System.err.println("Transaction aborted due to: " + e.getMessage());
        } finally {
            session.close();
        }

        mongoClient.close();
    }
}

3. 用户注册

场景描述:在用户注册时,需要同时在多个集合中写入数据。例如,需要在用户信息集合和用户角色集合中同时写入数据。确保两个集合的数据一致性,如果一个操作失败,则回滚所有操作。

代码示例

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

public class UserRegistrationExample {

    public static void main(String[] args) {

        // 创建 MongoClient
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");

        // 获取数据库和集合
        MongoDatabase database = mongoClient.getDatabase("userdb");
        MongoCollection<Document> users = database.getCollection("users");
        MongoCollection<Document> roles = database.getCollection("roles");

        // 开始会话
        ClientSession session = mongoClient.startSession();

        // 配置事务选项
        TransactionOptions txnOptions = TransactionOptions.builder()
                .readPreference(ReadPreference.primary())
                .readConcern(ReadConcern.LOCAL)
                .writeConcern(WriteConcern.MAJORITY)
                .build();

        try {
            // 开始事务
            session.startTransaction(txnOptions);

            // 执行用户注册操作
            users.insertOne(session, new Document("userID", "U1001").append("name", "John Doe"));
            roles.insertOne(session, new Document("userID", "U1001").append("role", "user"));

            // 提交事务
            session.commitTransaction();
            System.out.println("Transaction committed.");
        } catch (MongoException e) {
            // 回滚事务
            session.abortTransaction();
            System.err.println("Transaction aborted due to: " + e.getMessage());
        } finally {
            session.close();
        }

        mongoClient.close();
    }
}

4. 数据同步

场景描述:在分布式系统中,需要将数据从一个数据源同步到多个目标数据源。如果在同步过程中任何一个目标数据源失败,需要回滚所有已完成的同步操作,确保所有数据源的一致性。

代码示例

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

public class DataSyncExample {

    public static void main(String[] args) {

        // 创建 MongoClient
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");

        // 获取数据库和集合
        MongoDatabase sourceDatabase = mongoClient.getDatabase("sourcedb");
        MongoDatabase targetDatabase1 = mongoClient.getDatabase("targetdb1");
        MongoDatabase targetDatabase2 = mongoClient.getDatabase("targetdb2");

        MongoCollection<Document> sourceCollection = sourceDatabase.getCollection("data");
        MongoCollection<Document> targetCollection1 = targetDatabase1.getCollection("data");
        MongoCollection<Document> targetCollection2 = targetDatabase2.getCollection("data");

        // 插入初始数据
        sourceCollection.insertOne(new Document("dataID", "D1001").append("value", "sample data"));

        // 开始会话
        ClientSession session = mongoClient.startSession();

        // 配置事务选项
        TransactionOptions txnOptions = TransactionOptions.builder()
                .readPreference(ReadPreference.primary())
                .readConcern(ReadConcern.LOCAL)
                .writeConcern(WriteConcern.MAJORITY)
                .build();

        try {
            // 开始事务
            session.startTransaction(txnOptions);

            // 执行数据同步操作
            Document data = sourceCollection.find(session, new Document("dataID", "D1001")).first();
            if (data != null) {
                targetCollection1.insertOne(session, data);
                targetCollection2.insertOne(session, data);
            } else {
                throw new RuntimeException("Data not found")