首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB如何处理事务冲突?

MongoDB如何处理事务冲突?
EN

Stack Overflow用户
提问于 2018-11-08 06:11:49
回答 1查看 9K关注 0票数 8

如果两个线程确实读取和写入一个相同的文档:

代码语言:javascript
复制
try (ClientSession clientSession = client.startSession()) {
    clientSession.startTransaction();
    result = collection.find(clientSession, keyOfDoc);
    if (result blah blah blah) {
        // Change the doc
        collection.insertOne(clientSession, doc);
    }
    clientSession.commitTransaction();
}

从事务的目的来看,其中一个线程应该得到另一个线程的编辑版本。

但是,当两个线程启动事务时,它们都获得了一个读锁,然后读取了文档。这两个线程都得到了旧版本的文档。当他们需要编写文档时,他们尝试获取写锁,这将使事务不再是原子的。

另一种情况是书写冲突。

代码语言:javascript
复制
try (ClientSession clientSession = client.startSession()) {
    clientSession.startTransaction();
    collection.insertOne(clientSession, docDifferent);
    collection.insertOne(clientSession, docSame);
    clientSession.commitTransaction();
}

两个线程首先获得不同文档的写锁,然后获得同一文档的写锁,因为这是另一个事务冲突。

MongoDB使用什么级别的锁?我知道他们在2.2版本之前使用实例级别,而自4.0以来支持事务。如果MongoDB不使用数据库级锁,那么MongoDB如何处理事务冲突?或者,如果它使用数据库级别的锁,它如何处理读写冲突?

EN

回答 1

Stack Overflow用户

发布于 2018-11-09 05:12:00

我在MongoDB手册中找到了一些参考资料,解决了我自己的问题。

MongoDB使用什么类型的锁定? MongoDB使用多粒度锁定1,允许操作在全局、数据库或集合级别锁定,并允许单个存储引擎在集合级别以下实现自己的并发控制(例如,在WiredTiger中的文档级别)。

MongoDB使用从集合、数据库到全局的多个级别锁定。然而,尽管它支持多个级别的锁定,但您可以访问的唯一级别是集合级别,意味着您不能在事务中创建或删除数据库或集合。还意味着获取一个要锁定在集合中的文档将导致整个集合被锁定。

受限操作 在多文档事务中不允许执行下列操作:

  • 影响数据库目录的操作,例如创建或删除集合或索引。例如,多文档事务不能包含可能导致创建新集合的插入操作。 listCollections和listIndexes命令及其助手方法也被排除在外。
  • 非CRUD和非信息操作,如createUser、getParameter、count等及其助手.

为了解决冲突,MongoDB 向发生冲突时无法获得锁的访问者发送错误消息

重试事务 无论retryWrites是否设置为true,事务中的单个写入操作都是不可还原的。 如果操作遇到错误,则返回的错误可能有一个errorLabels数组字段。如果该错误是一个瞬态错误,则errorLabels数组字段包含"TransientTransactionError“作为一个元素,并且可以重新尝试整个事务。

这意味着当访问者接收到MongoException和异常.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)时,访问者应该关闭会话,并重新执行事务。来访者应该重新做一次,然后再做,直到成功为止。

您可以简单地使用此方法(从手动示例中修改):

代码语言:javascript
复制
public static <T> T transactWithRetry(Callable<T> transactional) throws Exception {
    while (true) {
        try {
            return transactional.call();
        } catch (MongoException ex) {
            if (!ex.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)) throw ex;
        }
    }
}

参见手册中的更多语言版本;)!

参考文献

交易- MongoDB手册

常见问题:并发- MongoDB手册

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53202345

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档