暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MongoDB4.2.0新功能事务支持

原创 Oracle 2023-05-10
445



mongodb4.2版本中增加了mongodb的多文档事务支持,在之前的版本中mongodb支持单文档事务,在单个文档上支持ACID原子性。在 4.2 中,分布式事务和多文档事务都是称为分布式事务。使得分布到集群中不同 sharded 的多文档 ACID 事务变得更加简单。MongoDB 通过二阶段提交的方式,实现在多个 Shard 间发生的修改,要么同时发生,要么都不发生,保证事务的 ACID 特性。除此之外,这个版本还删除事务的 16MB 总大小限制。在4.2 版本中,MongoDB 根据需要创建尽可能多的 oplog 实体(每个最大大小为 16MB),以封装事务中的所有写入操作。而在 MongoDB 4.0 中,MongoDB 为事务中的所有写操作创建单个条目,从而对事务强加 16MB 的总大小限制。




升级mongodb注意事项

  • 对应的mongodb驱动driver版本也需要升级到3.11以上。

  • 在mongodb单机版测试事务不支持,需要在分布式mongodb数据库上测试才可以。

mongodb复制集集群安装

笔者已经将mongodb复制集集群安装步骤总结成了markdown文章,文档地址如下

https://www.zybuluo.com/mdeditor#1622459-full-reader


项目依赖

            <dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>3.11.0</version>
    </dependency>


    代码测试清单如下

      package io.jopen.db.mongo.transaction;


      import com.mongodb.*;
      import com.mongodb.client.*;
      import com.mongodb.client.MongoClient;
      import org.bson.Document;
      import org.junit.Before;
      import org.junit.Test;


      /**
      * 多文档事务测试
      * https://www.zybuluo.com/mdeditor#1622459-full-reader
      *
      * @author maxuefeng
      * @since 2019/10/16
      */
      public class DistributeTransactionTest {


      private String uri = "mongodb://192.168.74.136:27018,192.168.74.138:27018,192.168.74.139:27018";
      private ConnectionString connectionString = new ConnectionString(uri);


      private MongoClient client = null;


      @Before
      public void before() {
      client = MongoClients.create(connectionString);
      }


      /**
      * For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
      * String uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/admin?replicaSet=myRepl";
      * For a sharded cluster, connect to the mongos instances; e.g.
      * String uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017:27017/admin";
      */
      @Test
      public void testTransaction() {


      client.getDatabase("mydb1").getCollection("foo").withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0));
      client.getDatabase("mydb2").getCollection("bar").withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0));


      final ClientSession clientSession = client.startSession();


      TransactionOptions txnOptions = TransactionOptions.builder()
      .readPreference(ReadPreference.primary())
      .readConcern(ReadConcern.LOCAL)
      .writeConcern(WriteConcern.MAJORITY)
      .build();


      TransactionBody txnBody = (TransactionBody<String>) () -> {


      // 创建集合
      MongoCollection<Document> coll1 = client.getDatabase("mydb1").getCollection("foo");
      MongoCollection<Document> coll2 = client.getDatabase("mydb2").getCollection("bar");


      coll1.insertOne(clientSession, new Document("abc", 1));
      // 第一条数据插入成功
      System.err.println("data insert success");


      // 抛出运行时异常
      double a = 10 0;


      // 如果上一条数据插入成功 下一条数据插入失败,事务需要回滚
      coll2.insertOne(clientSession, new Document("xyz", 999));
      return "Inserted into collections in different databases";
      };
      try {
      clientSession.withTransaction(txnBody, txnOptions);
      } catch (RuntimeException e) {
      e.printStackTrace();
      } finally {
      clientSession.close();
      }
      }
      }


      如上所示 ,如果第一个文档数据插入成功,则会打印data  insert success,在下面有一个运行时异常的语句double a = 10 / 0;如果运行出现异常,我们期望的结果是两条语句插入的数据都不可以成功。但在逻辑上来说第一条数据插入语句是执行成功了的。测试结果如下

        data  insert success
        java.lang.ArithmeticException: by zero
        at io.jopen.db.mongo.transaction.DistributeTransactionTest.lambda$testTransaction$0(DistributeTransactionTest.java:60)
        at com.mongodb.client.internal.ClientSessionImpl.withTransaction(ClientSessionImpl.java:194)
        at io.jopen.db.mongo.transaction.DistributeTransactionTest.testTransaction(DistributeTransactionTest.java:67)

        data  insert success被打印出来了,从逻辑上来说第一条语句插入成功,但正如我们期望的是它是以事务的形式执行的数据修改操作,所以一条数据都没有插入。

        「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
        关注作者
        【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论