You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决更新已有记录时出现的MongoBulkWriteException?

解决MongoBulkWriteException(code 16837):Cannot update 'version' and 'version' at the same time

嘿,这个错误我太熟了!MongoDB返回的code 16837说白了就是:你在同一条批量更新请求里,重复对version字段执行了更新操作——可能是不小心写了两次version的赋值,或者用了不同的更新操作符(比如$set+直接赋值)同时修改这个字段。

结合你堆栈里的Grails框架信息,这种情况大概率出在这几个场景里:

  • 你手动在更新逻辑里重复设置了version字段(比如Domain对象属性赋值+updateAll参数里又写了一遍)
  • 用Grails的查询API构建批量更新时,不小心在更新条件和更新内容里都包含了version的重复操作
  • 自定义的Domain映射或者第三方插件搞出了问题,导致ORM生成的MongoDB语句重复操作version

给你几个具体的排查和解决步骤:

1. 先检查批量更新的代码逻辑

找到你触发批量写入的代码块(比如调用bulkUpdate、updateAll或者手动构建BulkOperations的地方),仔细看更新的字段映射:

  • 错误示例(Grails里的常见坑):
    // 踩坑:更新内容里重复设置version,或者同时用了直接赋值和$set修改version
    YourDomainClass.updateAll(
        [version: 1], 
        [version: 2, $set: [version: 2, name: "newName"]]
    )
    
  • 修正后的正确写法:
    // 方式一:直接指定version更新(适合乐观锁场景)
    YourDomainClass.updateAll(
        [version: 1], 
        [version: 2]
    )
    // 方式二:用$set统一管理更新字段
    YourDomainClass.updateAll(
        [version: 1], 
        [$set: [version: 2, name: "newName"]]
    )
    

2. 检查Domain类的乐观锁配置

Grails默认给Domain类启用乐观锁(靠version字段),如果你的Domain类里重复定义了version,或者在mapping块里做了错误配置,也会触发这个问题:

class YourDomainClass {
    Integer version
    // ...其他字段

    static mapping = {
        version column: 'version' // 确保这里只配置一次,别重复写!
    }
}

3. 打印实际发送给MongoDB的语句

如果找不到问题,就开日志看真实的更新语句!在application.yml里加这段配置:

logging:
    level:
        org.grails.datastore.mapping.mongo: DEBUG

运行代码后,看日志里的MongoDB更新请求,一眼就能看到是不是有重复的version字段更新。

4. 处理乐观锁的批量冲突

如果是批量更新时多条记录的乐观锁版本不匹配,记得确保每条更新的version条件和新值是对应的,别让同一条记录被多次修改。实在不行可以拆分批量更新为单条的findOneAndUpdate,保证原子性。

总的来说,这个错误就是更新语句里的字段重复,找到重复设置version的地方改了就行。要是还搞不定,把你的批量更新代码贴出来,我帮你再瞅一眼!

内容的提问来源于stack exchange,提问作者Kapil Arora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:30:42