这种操作在mongodb中用事务好,还是加锁好?
发布于 6 年前 作者 lovegnep 5332 次浏览 来自 问答

假设集合A中有文档a1,集合B中有文档b1 如果a1中的field1字段大于10,则更新b1文档,否则啥也不做。


我现在的做法是对a1文档加锁,然后再进行查询a1(加锁和查询一条语句),修改b1,最后释放锁 缺点:1. 所有涉及到修改a1的地方都要加锁,2. 有可能死锁

现在mongodb支持事务了,我想用事务将查询和修改这两个操作包起来,但感觉大材小用了,各位有什么建议吗?

8 回复

没人遇到过吗?

像这种事情加个if判断一下不就可以了么

mongodb 官方对类似的问题其实有一个解答 如果你需要有强一致性的地方,你可以在同一个文档中进行原子操作 比如这个样子 更新a1 前,判断更新之后的值是否会大于10,如果大于,那么在a1中加一个字段,用于标识对应b1文档有无进行更新 执行完毕后,再去更新b1,再回来更新a1中的标识

或者麻烦一点可以使用两段提交

当然一定要用事务也是可以的

@hewentaowx 大兄弟,这些操作都是异步的呀。你第一步查询完,可能另外一个服务器已经更新了a1

来自酷炫的 CNodeMD

@aojiaotage 其实你说的这个和我说的锁是一样的,我就是这样做的。 我想用事务把这两个操作包起来,但在事务执行的过程中会不会也有其他操作修改了a1?

来自酷炫的 CNodeMD

@lovegnep 我知道是异步 async/await 包一层不就可以了么

这个不是事务解决的问题,事务主要是解决业务失败可以回滚的操作,或者撤销操作,用户反悔的或者其它系统导致业务需要复位的情况。 你的这个问题是数据一致性问题,目前我用的方式,有2种解决思路 1、如你所说,加锁,不过我的锁比较特殊,是在redis 放入一个a1的key,每次操作b1文档时候都去检查一下,如果没有就可以,如果有就撤销,操作完清理key。 2、采用消息队列方式,所有操作进入队列,按照顺序,逐一执行,不存在竞争。。。安安心心干活,就是要额外增加一个消息队列的维护,采用redis 和 rabbitMQ 都可以。。。

@cnlile 假设现在有两个业务操作都涉及到修改a1文档 如果用你所说的消息队列那就是将这两个操作连同本文提到的操作都放入消息队列,串行处理吗?

消息队列这种操作是把分布式环境下的任务统一交给一个地方串行处理了,感觉会影响性能吧。

回到顶部