读写锁

Mongodb使用读写锁来来控制并发操作:

当进行读操作的时候会加读锁,这个时候其他读操作可以也获得读锁。但是不能或者写锁。

当进行写操作的时候会加写锁,这个时候不能进行其他的读操作和写操作。

所以按照这个道理,是不会出现同时修改同一个文档(如执行++操作)导致数据出错的情况。

而且按照这个道理,因为写操作会阻塞读操作,所以是不会出现脏读的。

但是mongodb在分片和复制集的时候会产生脏读,后面在研究。

读写锁的粒度:

在2.2之前的版本,一个mongodb实例一个写锁,多个读锁,在2.2-3.0的版本,一个数据库一个写锁,多个读锁,在3.0之后的版本,WiredTiger提供了文档(不是集合)级别的锁。

findAndModify

db.collection.findAndModify({

query: <document>,

sort: <document>,

remove: <boolean>,

update: <document>,

new: <boolean>,

fields: <document>,

upsert: <boolean>,

bypassDocumentValidation: <boolean>,

writeConcern: <document>,

collation: <document>

});

:documentsort:

。可选的。以此参数指定的排序顺序修改第一个文档。

:document::

document。可选的。 要返回的字段的子集。 如:fields: {<field1>: 1, <field2>: 1, ... }

book = {

_id: 123456789,

title: "MongoDB: The Definitive Guide",

author: [ "Kristina Chodorow", "Mike Dirolf" ],

published_date: ISODate("2010-09-24"),

pages: 216,

language: "English",

publisher_id: "oreilly",

available: 3,

checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]

}

你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。

在同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:

db.books.findAndModify ( {

query: {

_id: 123456789,

available: { $gt: 0 }

},

update: {

$inc: { available: -1 },

$push: { checkout: { by: "abc", date: new Date() } }

}

} )

 

执行多个写入操作

 

首先,原则上说Mongdb没有事务的概念。

事务有ACID的概念,比如原子性,一个事务要么全部成功,要么全部失败。

如,考虑一个转账的业务,从A转账100到B,将分为两步:

A = A - 100;

B = B + 100;

在Mongdb中,如果A = A - 100;执行完,将会直接入库生效,没有回滚段的概念,所以如果此时B = B + 100;出现了问题,是不能回滚上一步A的操作的。

Mongdb在执行多个更新的时候是没有原子性的。

 

一个写入操作更新了多个文档:

当单个写入操作修改多个文档时,每个文档的修改是原子的,但整个操作不是原子的,而其他操作可能会交错。 但是,您可以使用$ isolation操作符隔离影响多个文档的单个写入操作。

当Mongodb执行影响多个文档的写入操作的时候,如果在中间某一个文档出现了错误,那么不会回滚之前的提交。之前的提交已经入库了。

MongoDB不隔离多文档写入操作,具有以下特点:

非时间点读操作。其中一假设读取操作在时间t1开始,并开始读取文档。写操作然后在稍后的时间t2向个文档提交更新。读操作可能会看到写操作的更新版本,因此读取操作没有时间点的概念。

读取可能会丢失在读取操作过程中更新的匹配文档。

使用$ isolation来保证隔离性:

使用$isolated操作符可以保证单个写入操作修改多个文档的时候不被交错。

$isolated其实是在整个数据库(Mongodb的手册对这点说明不清楚,也可能是在集合层面加独占锁,但是有一点文档中是说明的,不论在哪个层面加独占锁,都会导致真个数据库单线程化)加独占锁(即使是对于WiredTiger存储引擎也是),在这期间不能进行其他任何的读写操作。所以如果$isolated的操作执行的时间过长,会大大的影响系统的并发性能。

例子:

db.foo.update(
    { status :
"A" , $isolated :
1 },
    { $inc : { count :
1 } },
    { multi:
true }
)

注:上面说的影响不是说可以保证多个文档更新的原子性,$ isolation隔离操作符不为写入操作提供"all-or-nothing"原子性(原子性的定义是要么全部成功,要么全部失败,$isolation不能保证出错回滚)。没有$isolation运算符,多更新将允许其他操作与此更新交错。 如果这些交错操作包含写入,则更新操作可能会产生意外的结果。 通过指定$ isolated,您可以保证整个多重更新的隔离。

总结如下:

  • $ isolation不保证多个文档操作的原子性。
  • $ isolation保证多个文档操作不会被跟其他操作交错。
  • $ isolation保证此操作在进行到某一个文档的更新的时候,在不提交或者回滚之前,不会被客户端看到。也就是说不会导致这个文档的查询产生脏读。(这一段是我的理解 不一定对)

   

$isolated使用的场景很苛刻。

由于单个文档可以包含多个嵌入文档,单个文档的原子性对于许多实际使用情况是足够的。 对于一系列写入操作必须在单个事务中操作的情况,您可以在应用程序中实现两阶段提交。

但是,两阶段的提交只能提供类似事务的语义。 使用两阶段提交确保数据一致性,但是在两阶段提交或回滚期间,应用程序可以返回中间数据。

 

 

副本集中使用readConcern:

 

在使用副本集的时候,写入操作只写入到master节点,slaver节点从master节点同步数据,所以读操作可能读取到没有同步到其他slaver的数据。

readConcern:读隔离(

readConcern选项可用于以下操作:

用于副本集和副本集分片的readConcern查询选项确定从查询返回哪些数据。

readConcern级别:

"local":默认。该查询返回实例的最新数据。不保证数据已写入大多数副本集成员(即可以回滚)。

"majority":该查询会将实例的最新数据确认为已写入副本集中的大多数成员。要使用majority级别,您必须使用--enableMajorityReadConcern命令行选项启动mongod实例(如果使用配置文件,则将replication.enableMajorityReadConcern设置为true)。

"linearizable"(add in version3.4):该查询返回反映所有成功写入的数据。

   

这么说如果配置了linearizable 那么针对一个集合的查询就可以避免脏读了。因为Mongdb没有事务,所以也就不存在幻读和不可重复读的定义了。不过这个功能是在当前最新的3.4版本才有的。

 

readConcern 解决什么问题?

的初衷在于解决『脏读』的问题,比如用户从 MongoDB 的 primary 上读取了某一条数据,但这条数据并没有同步到大多数节点,然后 primary 就故障了,重新恢复后 这个primary 节点会将未同步到大多数节点的数据回滚掉,导致用户读到了『脏数据』。

当指定 readConcern 级别为 majority 时,能保证用户读到的数据『已经写入到大多数节点』,而这样的数据肯定不会发生回滚,避免了脏读的问题()readConcern 能保证读到的数据『不会发生回滚』,但并不能保证读到的数据是最新的,这个官网上也有说明:

在使用副本集的时候,无论读取关注级别如何,节点上的最新数据可能不会反映系统中最新版本的数据。

有用户误以为,指定为 majority 时,客户端会从大多数的节点读取数据,然后返回最新的数据。

实际上并不是这样,无论何种级别的 注意事项

  1. 检索事务开始:

var t = db.transactions.findOne( { state: "initial" , source: "A", destination: "B"} )

  1. Update transaction state to pending:


 

db.transactions.update(

{ _id: t._id, state: "initial" },

{

$set: { state: "pending" },

$currentDate: { lastModified: true }

}

)

WriteResult
nnModified1


nMatchednModified0

  1. Apply the transaction to both accounts.


 

db.accounts.update(

{ _id: t.source, pendingTransactions: { $ne: t._id } },

{ $inc: { balance: -t.value }, $push: { pendingTransactions: t._id } }

)

db.accounts.update(

{ _id: t.destination, pendingTransactions: { $ne: t._id } },

{ $inc: { balance: t.value }, $push: { pendingTransactions: t._id } }

)

  1. Update transaction state to applied

db.transactions.update(

{ _id: t._id, state: "pending" },

{

$set: { state: "applied" },

$currentDate: { lastModified: true }

}

)

  1. remove both accounts' list of pending transactions


 

db.accounts.update(

{ _id: t.source, pendingTransactions: t._id },

{ $pull: { pendingTransactions: t._id } }

)

db.accounts.update(

{ _id: t.destination, pendingTransactions: t._id },

{ $pull: { pendingTransactions: t._id } }

)

  1. Update transaction state to done.


 

db.transactions.update(

{ _id: t._id, state: "applied" },

{

$set: { state: "done" },

$currentDate: { lastModified: true }

}

)

Mongodb中的 原子性 隔离性的更多相关文章

  1. Mongodb的锁 原子性 隔离性 一致性

    读写锁 Mongodb使用读写锁来来控制并发操作: 当进行读操作的时候会加读锁,这个时候其他读操作可以也获得读锁.但是不能或者写锁. 当进行写操作的时候会加写锁,这个时候不能进行其他的读操作和写操作. ...

  2. 跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现

    提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一致性Consiste ...

  3. ACID隔离性

    数据库ACID 一致性 原子性  隔离性  持久性 隔离性: 1.读未提交 2.读已提交 3.可重复读 4.串行 读未提交:容易引起脏读 读已提交:容易引起幻读(前后读到的行数不一致) 场景: A事务 ...

  4. 事务四大特征:原子性,一致性,隔离性和持久性(ACID)

    一.事务 定义:所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位. 准备工作:为了说明事务的ACID原理,我们使用银行账户及资金管理的案例进行分析. [sql] ...

  5. 事务的四大属性ACID即事务的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability.。

    事务的四大属性ACID即事务的原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持久性(Durability.. 原子性(Atomicity) 原子性是指事 ...

  6. 数据库事务ACID特性(原子性、一致性、隔离性、持久性)

    ACID特性: 原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持久性(Durability) 原子性:一个事务必须被视为一个不可分割的最小工作单元,整个 ...

  7. acid-事务的原子性、一致性、隔离性、持久性

    博客分类: oracle-dba   原子性  多个事情组成一个单元,要么同时成功或失败,不能只运行其中一个 一致性  事务处理要将数据库从一种状态转变为另一种状态. 一旦提交了修改数据,那么其它人读 ...

  8. ACID 原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。

    https://en.wikipedia.org/wiki/ACID https://zh.wikipedia.org/wiki/ACID //ACID compliant , row-level l ...

  9. mysql中不同事务隔离级别下数据的显示效果--转载

    事务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都 ...

随机推荐

  1. ivew Tooltip

    在使用ivew的Tooltip时发生错位,添加属性transfer,避免受父样式影响 发生如上错误时,只需添加属性transfer无需赋值

  2. codeblocks报错:cannot open output file bin\Debug\2.exe Permission denied

    在任务管理器中也找不到正在执行的任务,以为清除了,但是重新编译文件报错. 解决办法: 打开W+R窗口,输入taskkill -IM 2.exe /F

  3. 工具类:mybatis中使用Threadlocal开启session及关闭session

    1.线程容器,给线程绑定一个Object 内容,后只要线程不变,可以随时取出. 1.1 改变线程,无法取出内容. final ThreadLocal threadLocal = new ThreadL ...

  4. 周强 201771010141面向对象程序设计(java)》第十七周学习总结

    线程同步 多线程并发运行不确定性问题解决方案:引入线 程同步机制,使得另一线程要使用该方法,就只 能等待. ⚫ 在Java中解决多线程同步问题的方法有两种: 1.- Java SE 5.0中引入Ree ...

  5. HslCommunication组件库使用说明 (转载)

    一个由个人开发的组件库,携带了一些众多的功能,包含了数据网络通信,文件上传下载,日志组件,PLC访问类,还有一些其他的基础类库. nuget地址:https://www.nuget.org/packa ...

  6. seg代码配置的踩坑记录

    01. SEGMENTATION FAULT 正在配置OCNET的代码,在自己的本地运行没有任何问题,但是在服务器上一直报错:SEGMENTATION FAULT 这属于很概括的报错,无法直接看明白到 ...

  7. svg 图片

    https://studio.qcloud.coding.net/rs2/d67e3c26b502365f8ab7c05d71c70471.svg 腾讯编辑器loading页面的svg

  8. Favorite Donut(HDU 5442)最小表示法+二分

    题目给出一个字符串,由a~z表示甜度,随字典序增大,字符串首尾相连形成一个圈,要求从一个位置开始字典序最大的字符串,输出位置以及是顺时针还是逆时针表示.顺时针用0表示,逆时针用1表示. 此题只需要查找 ...

  9. getRealPath()和getContextPath()的区别

    转载自:http://sucre.iteye.com/blog/319178 在程序中常常要获取文件的路径,有的时候需要用到相对路径而有的时候就要用到绝对路径,一提到绝对路径大家一定想到了getRea ...

  10. 多管齐下显神威-2017逐浪CMS开启全新建站与WEB技术革命

    培训班里说百遍,不如商业场景来检验. PS.AI.JS工具齐上阵,一统逐浪CMS全网中间件. 从逐浪软件创业团队成立.到逐浪CMS产品,以企业形式运营,历经十二载风雨,作为华文世界排名第一的dotNE ...