工业设计相关网站,国外的哪个网站可以做跳转,wordpress 制作模板教程,济南 网站开发前言
在 MongoDB 中#xff0c;对单个文档的操作都是原子的。因为可以在单个文档结构中使用内嵌文档和数据获得数据之间的关系#xff0c;所以不必跨多个文档和集合进行范式化#xff0c;这种结构特性#xff0c;避免了很多场景中的对多文档事务的需求。
对于需要多个文档…前言
在 MongoDB 中对单个文档的操作都是原子的。因为可以在单个文档结构中使用内嵌文档和数据获得数据之间的关系所以不必跨多个文档和集合进行范式化这种结构特性避免了很多场景中的对多文档事务的需求。
对于需要多个文档进行原子读写的场景MongoDB 中引入了多文档事务和分布式事务。 在4.0版本中MongoDB支持副本集上的多文档事务 在4.2版本中MongoDB 引入了分布式事务增加了对分片集群上多文档事务的支持并合并了对副本集上多文档事务的现有支持事务可以跨多个操作、集合、数据库、文档和分片使用这种方式事务的实现主要是借助于两阶段提交协议2PC实现的。
如何使用
MongoDB 中从 4.0 开始支持了事务这里来看看 MongoDB 中的事务是如何使用的呢
首先登陆 MongoDB 命令行
mongo -u name --port 27017 --host 127.0.0.1 admin -p pass1、打开 session
session db.getMongo().startSession( { readPreference: { mode: primary } } );2、将需要操作的 collection 进行变量绑定
testCollection session.getDatabase(gleeman).test_explain;
test1Collection session.getDatabase(gleeman).test_explain_1;3、开始事务标注指定MVCC的模式写模式
session.startTransaction( { readConcern: { level: snapshot }, writeConcern: { w: majority } } );4、拼接执行语句将需要执行的语句进行事务封装
try (ClientSession clientSession client.startSession()) {clientSession.startTransaction();collection.insertOne(clientSession, docOne);collection.insertOne(clientSession, docTwo);clientSession.commitTransaction();
}5、提交事务
session.commitTransaction();6、关闭session
session.endSession();事务的原理
MongoDB 中的 WiredTiger 存储引擎是目前使用最广泛的这里主要介绍下 WiredTiger 中事务的实现原理。
WiredTiger 存储引擎支持 read-uncommitted 、read-committed 和 snapshot 3 种事务隔离级别MongoDB 启动时默认选择 snapshot 隔离。
事务和复复制集以及存储引擎之间的关系
1、事务和复制集
复制集配置下MongoDB 整个事务在提交时会记录一条 oplog包含了事务所有的操作备节点拉取 oplog并在本地重放事务操作。事务 oplog 包含了事务操作的 lsidtxnNumber以及事务内所有的操作日志 applyOps 字段。
WiredTiger 是如何实现事务和 ACID 呢。WiredTiger 事务主要使用了三个技术 snapshot(事务快照)、MVCC (多版本并发控制)和 redo log(重做日志)。同时为了实现这三个技术还定义了一个基于这三个技术的事务对象和全局事务管理器。
wt_transaction{transaction_id: // 本次事务的全局唯一的ID用于标示事务修改数据的版本号snapshot_object: // 当前事务开始或者操作时刻其他正在执行且并未提交的事务集合,用于事务隔离operation_array: // 本次事务中已执行的操作列表,用于事务回滚。redo_log_buf: // 操作日志缓冲区。用于事务提交后的持久化State: // 事务当前状态
}
WiredTiger 中的 MVCC 是基于 key/value 中 value 值的链表每个链表单元中存储有当先版本操作的事务 ID 和操作修改后的值。
wt_mvcc{transaction_id: // 本次修改事务的IDvalue: // 本次修改后的值
}WiredTiger 中数据修改都是在这个链表中进行 append 操作每次对值的修改都是 append 到链表头每次读取值的时候读是从链表头根据对应的修改事务 transaction_id 和本次事务的 snapshot 来判断是否可读如果不可读向链表尾方向移动直到找到都事务可以读到的数据版本。
什么是 snapshot 呢
事务开始或者结束操作之前都会对整个 WiredTiger 引擎内部正在执行的或者将要执行的事务进行一次快照保存当时整个引擎的事务状态确定那些事务是对自己可见的哪些事务是自己不可见的。
WiredTiger 中的事务隔离级别
传统的事务级别都分成下面四种读未提交read uncommitted、读提交read committed、可重复读repeatable read和串行化serializable 。 读未提交一个事务还没提交时它的变更就能被别的事务看到读取未提交的数据也叫做脏读 读提交一个事务提交之后它的变更才能被其他的事务看到 可重复读一个事务执行的过程中看到的数据总是跟这个事务在启动时看到的数据是一致的在此隔离级别下未提交的变更对其它事务也是不可见的此隔离级别基本上避免了幻读 串行化这是事务的最高级别顾名思义就是对于同一行记录“写”会加“写锁”“读”会加“读锁”。当出现读写锁冲突的时候后访问的事务必须等前一个事务执行完成才能继续执行。
我们熟知的 MySQL 对于事务隔离级别的实现可重复读 和 读提交 主要是通过 MVCC 来实现MVCC 的实现主要用到了 undo log 日志版本链和 Read View。串行化 和 读未提交主要实现方式是通过加锁来实现的。
其中 Read View 可以在理解为一个数据的快照可重复读隔离级别会在每次启动的事务的时候生成一个 Read View 记录下当前事务启动瞬间当前所有活跃的事务 ID。具体细节可参见 MySQL中的事务的隔离级别
WiredTiger 存储引擎支持 read-uncommitted、read-committed 和 snapshot 3种事务隔离级别MongoDB 启动时默认选择 snapshot 隔离。 Read-Uncommited读未提交一个事务还没提交时它的变更就能被别的事务看到读取未提交的数据也叫做脏读WiredTiger 引擎在实现这个隔方式时就是将事务对象中的 snap_object.snap_array 置为空即可那么在读取 MVCC list 中的版本值时总是读取到 MVCC list 链表头上的第一个版本数据这样就总是能读取到最新的数据了 read-committed一个事务提交之后它的变更才能被其他的事务看到这种对于一个长事务可能存在多次读取读取到的值不一样因为每次读取都是读取的最新提交的数据WiredTiger 引擎在实现该事务隔离级别就是在事务在每次执行之前都对系统机型一次快照然后在这个事务快照中读取最新提交的数据 snapshot快照隔离方式一个事务开始时就进行一次快照并且只会进行一次快照这样事务看到的值提交版本这个值在整个事务过程中看到的都是一样
WiredTiger 中对于事务的实现也是基于 MVCC 实现的MVCC 可以提供基于某个时间点的快照有了这个快照就能确定当前事务能看到的数据了通过这个来实现对应的事务隔离级别这点也个人感觉和 mysql 中的 Read View 类似不展开分析了。
WiredTiger 没有使用传统的事务独占锁和共享访问锁来保证事务隔离而是通过对系统中写事务的 snapshot 截屏来实现。这样做的目的是在保证事务隔离的情况下又能提高系统事务并发的能力。
WiredTiger 事务过程
一般事务有三个阶段开启事务执行事务提交事务。如果事务执行失败会进行事务的回滚操作事务正常执行最近进行事务的提交 (commit) 即可。
事务开启
事务开启的过程中首先会为事务创建一个事务对象并把这个对象加入到全局的事务管理器当中然后根据配置确定事务的隔离级别和 redo_log 的刷盘方式并将事务状态设置成执行状态最后判断事务的隔离级别如果是 snapshot 级的事务隔离在本次事务执行之前会创建一个系统并发事务的 snapshot 截屏保存当时整个引擎的事务状态确定那些事务是对自己可见的哪些事务是自己不可见的。
事务执行
事务在执行阶段如果是读操作不做任何处理因为读操作不需要回滚和提交。如果是写操作WiredTiger 会对每个操作做详细的记录。
这里就会用使用到上面介绍的事务对象(wt_transaction)中的 operation_array 和 redo_log_buf。
operation_array主要记录本次事务中已经提交的操作列表数组单元中会包含一个指向 MVCC list 对应修改版本值的指针用于事务的回滚。
redo_log_buf: 操作日志缓冲区。用于事务提交后的持久化。
来描述下具体的更新操作过程
1、创建一个 mvcclist 的值对象 update
2、根据事务对象的 transaction_id 和事务状态判断是为本次事务创建写的事务id,如果没有为本次事务分配一个事务id,并将事务的状态设置成 HAS_TXN_ID 状态
3、将本次事务的 ID 设置到 update 单元中作为 mvcc 版本号
4、同时会创建一个 operation 对象这个对象的指针会指向 update,这个对象会加入到 operation_array 中用来进行操作事务的回滚
5、update 会被加入到 mvcclist 的头部
6、最后会写一条 redo_log 到本次事务的 redo_log_buffer 当中。
事务提交
提交事务对象中的 redo_log_buf 中的数据到 redo_log_file(重做日志中)并将 redo_log_file 持久化到磁盘上清除提交事务对象的 snapshot再将事务对象的transaction_id 设置成 WT_TNX_NODE保证其他事务在创建 snapshot 时本次事务的状态是已提交的状态。
事务回滚
WiredTiger 引擎对事务的回滚过程比较简单首先遍历 operation_array 对每个数组单元对应的 update 事务 id 设置一个 WT_TXN_ABORTED ,标识 mvcc 对应的事务单元被回滚在其它事务进行 mvcc 读操作的时候跳过这个放弃的值即可整个过程是一个无锁的操作高效简洁。
事务日志(journal)
Journal 是一种 WALWrite Ahead Log事务日志目的是实现事务提交层面的数据持久化。
Journal 是 MongoDB 存储引擎层面的概念MongoDB 主要支持的 mmapv1、wiredtiger、mongorocks 等存储引擎都⽀持配置 Journal。MongoDB 可以基于 Journal 来恢复因为崩溃未及时写到磁盘的信息。
Journal 持久化的对象不是修改的数据而是修改的动作以日志形式先保存到事务日志缓存中再根据相应的配置按一定的周期将缓存中的日志数据写入日志文件中。
事务日志落盘的规则如下。
1、按时间周期落盘。
在默认情况下以50毫秒为周期将内存中的事务日志同步到磁盘中的日志文件。
2、提交写操作时强制同步落盘。
当设置写操作的写关注为j:true时强制将此写操作的事务日志同步到磁盘中的日志文件。
3、事务日志文件的大小达到100MB。
总结
1、在4.0版本中MongoDB支持副本集上的多文档事务
2、在4.2版本中MongoDB 引入了分布式事务增加了对分片集群上多文档事务的支持并合并了对副本集上多文档事务的现有支持事务可以跨多个操作、集合、数据库、文档和分片使用
3、MongoDB 中的 WiredTiger 存储引擎是目前使用最广泛的WiredTiger 存储引擎支持 read-uncommitted 、read-committed 和 snapshot 3 种事务隔离级别MongoDB 启动时默认选择 snapshot 隔离 Read-Uncommited读未提交一个事务还没提交时它的变更就能被别的事务看到读取未提交的数据也叫做脏读WiredTiger 引擎在实现这个隔方式时就是将事务对象中的 snap_object.snap_array 置为空即可那么在读取 MVCC list 中的版本值时总是读取到 MVCC list 链表头上的第一个版本数据这样就总是能读取到最新的数据了 read-committed一个事务提交之后它的变更才能被其他的事务看到这种对于一个长事务可能存在多次读取读取到的值不一样因为每次读取都是读取的最新提交的数据WiredTiger 引擎在实现该事务隔离级别就是在事务在每次执行之前都对系统机型一次快照然后在这个事务快照中读取最新提交的数据 snapshot快照隔离方式一个事务开始时就进行一次快照并且只会进行一次快照这样事务看到的值提交版本这个值在整个事务过程中看到的都是一样
4、WiredTiger 中对于事务的实现也是基于 MVCC 实现的MVCC 可以提供基于某个时间点的快照有了这个快照就能确定当前事务能看到的数据了通过这个来实现对应的事务隔离级别这点也个人感觉和 mysql 中的 Read View 类似不展开分析了
5、WiredTiger 没有使用传统的事务独占锁和共享访问锁来保证事务隔离而是通过对系统中写事务的 snapshot 截屏来实现。这样做的目的是在保证事务隔离的情况下又能提高系统事务并发的能力。
参考
【MongoDB事务】MongoDB事务 - MongoDB-CN-Manual 【WiredTiger的事务实现详解 】WiredTiger的事务实现详解_wiredtiger 事务-CSDN博客 【MongoDB中并发控制】MongoDB中并发控制MVCC_mongo的mvcc-CSDN博客