资讯专栏INFORMATION COLUMN

有坑勿踩(三)——关于数据更新

mengera88 / 807人阅读

摘要:前言数据更新,中的,对任何数据库而言都是最基本的操作。你并不能保证数据在被你读出来到写回去期间是否有别人已经改了数据库中的记录,这就是第一个风险,操作存在潜在的可能性会覆盖掉别人更新过的数据。

前言

数据更新,CRUD中的U,对任何数据库而言都是最基本的操作。看似简单的更新操作中会藏着哪些坑?今天聊一聊这个话题。

在写这个系列文章时,我会假设读者已经对MongoDB有了最基础的了解,因此一些基本名词和概念就不做过多的解释,请自己查阅相关资料。

数据更新方式

以shell为例,MongoDB的数据更新可以使用以下几种方式:

db..update()

db..updateMany()

db..updateOne()

db..save()

db..findAndModify()

前三种是由于历史原因产生的,实际上:

updateMany = update + {multi: true}

updateOne = update 或 update + {multi: false}

因为update本身的意义不够清楚,所以3.0以后才出现了updateManyupdateOne两个替代方法。这个方法没多少要说的,唯一要注意的就是,如果用update方法的话,不要忘记操作符($set, $inc等等),不然……
updateManyupdateOne则没有这个问题,缺了操作符会直接报错。

更新操作对比 update三兄弟和findAndModify

很多人的疑问可能都在这里,它们到底有什么区别,傻傻分不清楚。
首先参数不一样:

findAndModify

update

请阅读文档不多赘述。
其次功能不一样,
update只是更新操作,而findAndModify可以在找到结果后选择执行更新还是删除操作。说白了功能上findAndModify=updateOne+removeOne。注意它只能对单个文档进行操作。
无论更新还是删除,(『找到』『更新』)或(『找到』『删除』)都是原子性的,这点findAndModifyupdateOne/removeOne没有任何区别。区别只在于findAndModify在完成动作之后还可以选择把更新/删除之前或之后的文档返回给你。如果没有这个操作,那就必须先findupdate或者先updatefind,无论怎么做,都不能保证中间不被其他操作捷足先登。因此findAndModify在某些场景下是必要的,比如使用$inc生成递增序列(注意生成递增序列做ID不是个好想法,我在这个问题中做过解释)
因为findAndModify只针对单个文档,那么如果条件能找到多个文档怎么办?sort就用在这种场景下。

update和save

save实际上是一种特殊的update,即不带操作符的update。通俗地说叫『替换』。替换,代表你已经有这个文档完整的样子,即代表你已经把整个文档从数据库中读出来,在内存中进行了修改,然后完整替换回去。你并不能保证数据在被你读出来到写回去期间是否有别人已经改了数据库中的记录,这就是第一个风险,save操作存在潜在的可能性会覆盖掉别人更新过的数据。例如:

db.celebrity.findOne()
{
    _id: "孙悟空",
    title: "石猴"
    age: 500
}

你执行了:

var obj = db.celebrity.findOne({_id: "孙悟空"});
obj.title = "弼马温";
// 其他操作
db.celebrity.save(obj);

在『其他操作』的地方有人把孙悟空的title更新成了『齐天大圣』,很显然在你save的时候你会把它改回『弼马温』。

除了上述问题,save还带来一个额外的副作用,因为整个文档都保存进去了,意味着整个文档都会进入oplog,这会显著增加oplog的使用速度。因此过度使用save常常还会造成oplog不够用,需要很大的oplog才能足够保存24小时的信息。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/19495.html

相关文章

  • 有坑勿踩(一):MongoDB PSS vs PSA

    摘要:注意记住的作用始终是把集群中具有投票权的节点总数凑成奇数用,防止脑裂。其代表的意义是集群中必须有大多数节点收到并确认了一个写操作,这个写操作才算成功。无论源或者目标片中不能够满足大多数时,迁移都会失败。在有可能的情况下,应尽量使用代替。 前言 在技术社区混了这么长时间,因为一些常见的技术问题反复被问到,总是想写写文章把它们讲清楚。无奈很多时候看似基础的技术问题背后都隐藏着很深的原因,想...

    Freelander 评论0 收藏0
  • 有坑勿踩(二)——关于游标

    摘要:本质上所有查询的数据都是从游标来的。的作用是从游标中提取一批数据,具体提取多少则是由决定。同时注意我们已经有了一个游标。为了便于理解,我们下面还是称之为游标超时。 前言 聊一聊一个最基本的问题,游标的使用。可能你从来没有注意过它,但其实它在MongoDB的使用中是普遍存在的,也存在一些常见的坑需要引起我们的注意。 在写这个系列文章时,我会假设读者已经对MongoDB有了最基础的了解,因...

    bawn 评论0 收藏0
  • 小心,querySelector前方10米有坑

    摘要:但是,用获取到的集合却不是的。于是小伙们做起了实验,大致发现,如果对节点进行删除,那么是如果新增节点则不是。如果有新发现欢迎评论留言另一个值得注意的是关于和。从的文档上笼统来说,所有集合都可以叫做,不过需要注意如下 在写一个小组建的时候用到了document.querySelector,被小伙伴提醒说这个可能有坑,是啥呢?先来一篇MDN的文档解解馋:戳我戳我戳我>>>>>>>NodeL...

    int64 评论0 收藏0
  • 记录不存在则插入,存在则更新 → MySQL 的实现方式有哪些?

    摘要:需求背景环境版本开发规范公司后端开发规范有这么一点更新数据库表中数据的时候,不允许先删,然后批量插入需要将入参与表中数据比判断,找出哪些是新插入,哪些需要更新,哪些是删除的,然后再做对应的数据操作需求我们有表如下当商 ...

    pingan8787 评论0 收藏0

发表评论

0条评论

mengera88

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<