设为首页 收藏本站
查看: 1609|回复: 0

[经验分享] 在MongoDB中实现乐观并发控制

[复制链接]

尚未签到

发表于 2018-10-28 10:03:51 | 显示全部楼层 |阅读模式
  说起来,自从接触了MongoDB以后,我在大小项目中就再也没有接触过关系型数据库了。性能倒不是什么主要问题,主要是方便,例如我可以在MongoDB中直接保存数组,然后把其中的元素当作查询条件,而在关系型数据库中,则需要使用额外的表格,然后再JOIN等等。当然,在MongoDB中很难进行JOIN,于是对于某些场景下会略显麻烦,但在记忆中我似乎真没什么束手束脚的情况。这方面我还没有仔细分析,可能MongoDB支持保存复杂对象会有所帮助吧。以上都是废话,这里我简单谈一下如何在MongoDB中实现乐观并发控制。当然加入您对MongoDB的功能都有所了解,那么这种做法也是十分显而易见的。
  简单地说,“并发控制”便是避免在并发环境下某条记录被错误地覆盖。例如在一次“读取”、“修改”、“提交”的事务中,除非进行合理控制,否则可能其中某次提交的数据就遗失了。所谓“悲观”并发控制,则意味着在某次事务的“开始”和“提交”之间不会出现任何“读取”操作(即这条记录被锁定了),这自然不会有问题。而乐观并发控制,则保证的是在某次“读取”和“提交”之间没有进行任何“提交”操作,否则便会提交失败,于是当前事务便会重新从“读取”这个最早的步骤开始。此类概念(或者说并发处理方式)在许多地方都有体现,例如在普通的并发编程中,lock就近似于“悲观”并发控制,而“软件事务内存”则类似于“乐观”并发控制。
  如果要在普通的关系型数据库里实现乐观并发控制,我们一般需要为其加上一个额外的Version字段,它是整型,也可能是个时间戳。在更新某条记录时,我们将这个字段的“旧值”作为UPDATE语句的条件之一,同时这个字段也会写入新的值。如果这次更新影响了某条记录,那么表示更新成功,反之则表示这条记录已经被删除,或是在“读取”和“提交”之间遇到了其他提交操作。在SQL Server中存在一个Timestamp类型,这个类型的字段会在记录修改时自动更新。
  在MongoDB中的做法也没有太大区别,只是它的update语句并不会返回它所影响的记录数,于是我们必须额外进行一次查询,例如文档上所记载:
  

  
> t.update({_id: 1, version: 3}}, {$set: {Content: "New Content", version: 4}});
  
> db.$cmd.findOne({getlasterror: 1});
  
{"err":, "updatedExisting": true, "n": 1 , "ok": 1} // it worked
  

  
> t.update({_id: 1, version: 3}}, {$set: {Content: "New Content", version: 4}});
  
> db.$cmd.findOne({getlasterror: 1});
  
{"err":, "updatedExisting": false, "n": 0 , "ok": 1} // did not work
  

  我们可以在update语句后面跟上一句db.$cmd查询,如果它返回updatedExisting为true,则表示更新成功了。我一开始担心db.$cmd查询的结果是否准确:如果在update语句和db.$cmd查询之间,另外一个连接恰好也执行了一次update操作,那么db.$cmd返回的是哪次更新的结果?从后来从邮件列表中得知,db.$cmd查询是与连接相关,这便不会有问题了。不过值得注意的是,如果您使用的的驱动程序是“自动管理连接”的,则可能您在程序中发起的两次查询会使用两个不同的链接。不过我猜成熟的驱动应该都有办法解决这个问题,例如MongoDB的官方.NET驱动便可以要求直接返回db.$cmd查询的结果,或者在代码里显式“固定”某个链接。如今MongoDB的官方驱动已经十分完善,将MongoDB的功能体现地淋漓尽致,我也正在它的基础上更新EasyMongo(经过几个项目使用,感想不错),和之前的“民间驱动”相比省了不少心——顺便一提,官方驱动其实也借用了民间驱动的不少代码,即便它们之间的API有许多差异。
  除此之外,您也可以使用基于runCommand的findAndModify命令进行更新,更新条件自然同样需要包括版本号。如果更新成功,那么findAndModify命令则会返回“更新前”的数据,否则则返回空文档。一般来说,MongoDB的驱动也已经包含了runCommand命令,甚至对findAndModify的直接支持(例如官方的.NET驱动)。
  正如我一开始所说的那样,其实如果您了解MongoDB的功能,本文内容其实是十分显而易见的,的确就是这么简单。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-627392-1-1.html 上篇帖子: MongoDB Master/Slaver配置 下篇帖子: MongoDB 简介2
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表