[新]分析mongodb transaction WriteConflict问题

最近在项目尝试使用Mongodb的事务特性
遇到了一个情况,两个事务执行修改同一个数据的时候会返回下面的错误

org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 112 (WriteConflict): 'WriteConflict'

WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.,

在并发操作同一个文档的时候,有概率会出现上面的这些提示,然后在重试之后就会没有。

解读

目前mongodb的事务锁处理方式是:
https://docs.mongodb.com/v4.4...

In-progress Transactions and Write Conflicts

If a transaction is in progress and a write outside the transaction modifies a document that an operation in the transaction later tries to modify, the transaction aborts because of a write conflict.
If a transaction is in progress and has taken a lock to modify a document, when a write outside the transaction tries to modify the same document, the write waits until the transaction ends.

正在进行的事务和写入冲突(谷歌翻译)

如果事务正在进行并且事务外的写入修改了事务中的操作稍后尝试修改的文档,则事务会因写入冲突而中止。
如果一个事务正在进行并且已经锁定修改文档,那么当事务外部的写操作试图修改同一个文档时,写操作会一直等到事务结束。

简单来讲 如果两个事务修改同一个文档就会报写冲突,不支持MySql那样的行锁-悲观锁。

原因

Mongodb的事务属于乐观事务,不同于MySql悲观事务
Mongodb的事务使用的隔离级别为SI(Snapshot Isolation,篇外连接)

1、乐观事务会有冲突检测,检测到冲突则立即throw Conflict(也就是上面提到的WriteConflict)
2、乐观事务推崇的是更少的资源锁定时间,达到更高的效率,跟以往我们使用的MySql事务还是有比较大的区别的
3、所以可以理解不支持MySql那样的行锁-悲观锁

MongoDb官方推荐在driver层重试,也就是出现WriteConflict异常自动进行重试。

总结

也就是不管使用Java、.Net、Nodejs、C++等等语言,出现冲突需要执行重试

事务API:https://docs.mongodb.com/manu...

官方新增了一个叫withTransaction的API方法,这个是可以自动重试事务,如果是直接使用mongo-driver是可以看一下有没有这个方法,有就使用这个就行。

对于使用SpringBoot框架 重试Mongodb事务可以看这里:https://segmentfault.com/a/11...


篇外-事务参数解析

  # 事务存活最长时间(默认60秒)
  transactionLifetimeLimitSeconds: 秒 
  # 事务锁超时最长时间(默认5毫秒)
  maxTransactionLockRequestTimeoutMillis: 毫秒
  # 同时执行读事务的最大个数(建议设置大一些)
  wiredTigerConcurrentReadTransactions: 个数
  # 同时执行写事务的最大个数(建议设置大一些)
  wiredTigerConcurrentWriteTransactions: 个数

修改(以参数maxTransactionLockRequestTimeoutMillis为例子)

方式一:使用这个可以在线修改这个值

db.adminCommand( { setParameter: 1, maxTransactionLockRequestTimeoutMillis: 36000000} );

方式二:启动的时候加入参数

mongod --setParameter maxTransactionLockRequestTimeoutMillis=36000000

方式三:在(/etc/mongod.cnf)中加入一下配置(老版配置文件)

setParameter = maxTransactionLockRequestTimeoutMillis=36000000

方式四:在新版yaml配置文件(/etc/mongod.cnf)中加入一下配置(推荐)

setParameter:
  # 事务锁超时最长时间(毫秒)
  maxTransactionLockRequestTimeoutMillis: 36000000

集群

如果是副本集分片建议在每台服务器都执行相同的配置

随遇而安

27 声望
4 粉丝
0 条评论
推荐阅读
Springboot 解决mongodb transaction WriteConflict问题
Mongodb的事务属于乐观事务,不同于MySql悲观事务Mongodb的事务使用的隔离级别为SI(Snapshot Isolation,篇外连接)

岁月安然1阅读 5.4k评论 3

Mongodb-关联表查询
之前使用SQL语法来查询oracle、sqlserver、mysql表之间的关联,但是到mongodb之后完全无从下手,写法完全不一样,于是到网上查询mongodb关联表查询的写法,于是参考代码自己试着写了下,但是发现有好多问题,比如...

Awbeci2阅读 4.6k评论 1

(学习到实践)七、mongodb测试,php+nginx负载均衡的部署
从测试容器中匹配搜索得到 mongod.conf.orig,设置可以启动,网上查找配置项反不能启动,原因是配置是yaml格式!好像听说过。百度查询得到:官方配置说明,网站卡得出奇。

沧浪水阅读 2.9k

保姆级实战验证Mysql InnoDB四种事物隔离级别
事物:用来保证一组操作,要么全部成功要么全部失败隔离:因为在高并发情况下大概率会出现多个事物同时操作同一个数据,如果事物之间不进行隔离可能会出现意想不到的问题

idgq2阅读 533

封面图
MongoDB安装、启动、关闭、授权
安装参考[链接]配置文件 {代码...} 启动MongoDB {代码...} MongoDB的关闭方式kill进程模式(不建议使用) {代码...} 自带模式 {代码...} 注意: mongod进程收到SIGINT或SIGTERM信号,会做一些处理 切忌使用kill -9...

YYGP阅读 1.3k

mongoShake基于go实践应用
通过阿里云自研的MongoShake开源工具,您可以实现MongoDB数据库间的数据同步,该功能可用于数据分析、灾备和多活等业务场景。本文以云数据库MongoDB实例间的数据实时同步为例介绍配置流程。

金闽阅读 1k

mysql 事务隔离级别介绍
在 Repeatable Read 隔离级别下,事务开始时会获取一致性快照,并在事务结束之前保持这个快照。这意味着在事务执行期间,读取的所有数据都来自于这个快照,而不会受到其他事务的修改影响。因此,在这个隔离级别下...

无知阅读 877

随遇而安

27 声望
4 粉丝
宣传栏