MongoDB之bulkWrite探秘

MongoDB有很多有趣的内置方法,其中为了批量处理一些写入操作,并且可以按照一定顺序执行,自从3.2版本之后提供了该批量方法:bulkWrite。

它的语法很简单:


db.collection.bulkWrite(
   [ <operation 1>, <operation 2>, ... ],
   {
      writeConcern : <document>,
      ordered : <boolean>
   }
)

分别解释一下上述参数,
opertion 1, opertion 2:表示写入操作对象,例如插入数据的操作:

{ insertOne: { document: { _id: 3, type: "spider", size: "medium", price: 6 } } },

writeConcern:它表示写入设置,当有多个MongoDB节点(比如三个节点,其中一个primary节点)的时候,我们会定义什么才算是写入成功。从5.0版本之后,默认是{w: ‘majority’},也就是当大多数节点写入完成,则会返回写入结果。比如有三个节点,那么超过一半,也就是2个或者2个以上节点写入成功,则该写入操作才能算成功。

ordered:这个参数为true的时候代表这些写入操作是严格按照顺序串行执行的,也就是先执行operation 1,然后执行operation 2。并且在这个过程中如果有一个操作发生错误,则MongoDB返回结果并不执行剩余的写操作。

当odererd是false,代表这些写操作可以无序地并发执行,当有一个写操作发生错误,则MongoDB会继续执行完其他操作,最后返回错误和异常。

所以可以看出有序方式bulkWrite会比无序方式更慢,因为它会等待每一个写操作完成之后再返回最后的结果。

我们最近就遇到一个bulkWrite使用不当引起的问题,我们会批量insertOne一些商品到商品集合里面,发现所有的商品写入都没成功,数据库里面没有那些商品数据。要知道之前这个功能一直都是正常的。通过仔细排查发现,是因为有一部分商品数据在另外一个业务里面先写入了一部分,后面逻辑走到bulkWrite的时候就因为无法重复插入相同数据(unique key validation)而导致后续写入操作都失败了。

我们没有专门设置ordered参数,所以默认是true,也就是有序执行。所以当有错误发生的时候,后续的写入操作都不会执行了。恰好之前另外逻辑写入的那2个商品就是在这一些insertOne操作里面排最前面的两个,所以后面所有剩余的insertOne的商品数据都不会执行插入操作了。

最简单的解决办法就是设置ordered为false,这样就不会阻拦剩余写操作正常执行。

posted @ 2023-06-08 23:53  freephp  阅读(437)  评论(0编辑  收藏  举报