繁体   English   中英

MongoDB如何处理事务冲突?

[英]How does MongoDB deal with transactional conflicts?

如果两个线程都读取和写入同一文档:

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();
}

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

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

另一种情况是写 - 写冲突。

try (ClientSession clientSession = client.startSession()) {
    clientSession.startTransaction();
    collection.insertOne(clientSession, docDifferent);
    collection.insertOne(clientSession, docSame);
    clientSession.commitTransaction();
}

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

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

我在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)访问者应该关闭会话, .hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL) 做事务 访问者应该重做并重新发送,直到提交成功为止。

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

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手册

FAQ:并发 - MongoDB手册

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM