您的位置:首页 > 数据库 > Mongodb

遇到问题----MongoDB---JAVA--大批量操作先删后存时偶尔出现保存的文档也被删除

2017-06-16 10:46 573 查看

现象

这与MongoDB内部执行顺序的有关。

先说下我们的场景。数据库中有大量的数据需要 重新 更新。

我们使用的是java驱动,mongotemplate.save如果文档存在,则只会更新文档。

因为数据单个文档 的结构很复杂, 我们担心使用save不能正确的更新文档所以使用了关系型数据库上的操作逻辑。

就是在逻辑层,java操作中 执行先删除原文档再保存新文档(id)保持一致。

如果保存的文档 大小很大的时候是不会有问题的。

但是保存的文档太小时,大批量操作中 会出现 保存操作比 删除操作执行得快的情况。

我们期望的执行顺序应该是:

删除数据库中 编号为1的数据 ----->  保存 编号为1的数据

而现在出现的顺序为

保存 编号为1的数据  ----->  删除数据库中 编号为1的数据

导致了 保存的数据也被删除了。

原因

MongoDB与关系型数据库不同,MongoDB没有事务,所以 删除与保存 不是一个原子操作。

而且MongoDB的操作不关心 执行 是否成功。一般驱动中不提供操作返回值。

也就是说 对MongoDB发出指令后,它不会等待它返回结果才执行下一个指令,这样MongoDB的速度就很快,但也给我们带来了一些问题。

虽然 mongotemplate.remove比mongotemplate.save先发出(间隔估计只有0.2,总之间隔很短),但是在数据库层接收到指令时,有可能save会比remove执行得快,尤其是大数据量和加了索引等复杂情况下。

解决方案

后来调研了mongoTemplate.save方法,发现它是可靠的。
其实mongoTemplate.save方法在数据库层执行的 逻辑就是  先删除原文档再保存新文档。
而不是 每个字段去对比更新。
这样就不担心 复杂文档结构 更新 不一致了。

调研方法 
先保存
{"id":ObjectId("334232"),"filed1":1,"filed2":2}

然后使用 
save({"id":ObjectId("334232"),"filed1":new1});

如果save是每个字段去对比更新的话,就会变成
{"id":ObjectId("334232"),"filed1":new1,"filed2":2}

实际上文档变成了
{"id":ObjectId("334232"),"filed1":new1}

所以证明save并不是每个字段去对比更新。
而是当id相同时把原文档删除后保存新文档,id保持一致。

 也就是说 我们要 更新文档时,可以直接使用save方法即可,而不需要先remove再save。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐