在MongoDB中实现乐观并发控制

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介:

说起来,自从接触了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的功能,本文内容其实是十分显而易见的,的确就是这么简单。





















本文转自cnn23711151CTO博客,原文链接: http://blog.51cto.com/cnn237111/508397,如需转载请自行联系原作者


相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
NoSQL 安全 Java
SpringBoot系列(2)整合MongoDB实现增删改查(完整案例)
自己本科时候一直使用的是Mysql,目前的课题组使用的是MongoDB,因此就花了一部分时间整理了一下,实现springboot与MongoDB的整合,并且实现基本的增删改查操作,从头到尾给出一个完整的案例。
1052 0
SpringBoot系列(2)整合MongoDB实现增删改查(完整案例)
|
存储 NoSQL Java
mongodb基于地理位置查询实现围栏
mongodb基于地理位置查询实现围栏
1556 0
|
NoSQL 前端开发 Java
基于 Mongodb 实现商品管理系统之准备工作讲解|学习笔记
快速学习基于 Mongodb 实现商品管理系统之准备工作讲解
基于 Mongodb 实现商品管理系统之准备工作讲解|学习笔记
|
NoSQL 数据库连接 MongoDB
基于 Mongodb 实现商品管理系统之向数据库中添加商品编写讲解|学习笔记
快速学习基于 Mongodb 实现商品管理系统之向数据库中添加商品编写讲解
基于 Mongodb 实现商品管理系统之向数据库中添加商品编写讲解|学习笔记
|
NoSQL 数据库连接 MongoDB
基于Mongodb实现商品管理系统之根据商品编号删除商品编写讲解|学习笔记
快速学习基于Mongodb实现商品管理系统之根据商品编号删除商品编写讲解
基于Mongodb实现商品管理系统之根据商品编号删除商品编写讲解|学习笔记
|
NoSQL MongoDB Android开发
基于 Mongodb 实现商品管理系统之 Web 层编写讲解|学习笔记
快速学习基于 Mongodb 实现商品管理系统之 Web 层编写讲解
基于 Mongodb 实现商品管理系统之 Web 层编写讲解|学习笔记
|
存储 缓存 NoSQL
分布式服务器框架之Servers.Core中 实现Log模块设计 写入MongoDB数据库
游戏服务器中都需要用到Log模块,log模块存在的意义第一个是将log输出到控制台又或者是写入到log文件中,出了BUG方便定位;第二是常用于将用户的数据(例如玩家登录、道具购买量)将这种log统计到数据库中,方便统计用户留存信息、数据分析等。
|
NoSQL MongoDB 数据库
分布式服务器框架之Server.Core库中实现YFUniqueEntity、YFUniqueIDBase 管理MongoDB 自定义Id的自增
YFUniqueEntity是数据库中的结构,GetUniqueID函数中会根据Type和自增步长去数据库中寻找该类型的当前ID是多少,然后会用当前的Id去加上步长,把更新后的新ID插入到MongoDB中记录着ID的那张表里。
|
NoSQL MongoDB
分布式服务器框架之Servers.Core库中实现 MongoEntityBase 实现阻塞 异步对MongoDB的增删改查
YFMongoDBModelBase类是个模板类,对模板参数进行了约束YFMongoEntityBase,必须要继承YFMongoEntityBase
|
JSON NoSQL MongoDB
分布式服务器框架之Servers.Core库中实现MongoDB的ObjectId和Json转换
分布式服务器框架之Servers.Core库中实现MongoDB的ObjectId和Json转换