当前位置: 首页 > article >正文

MongoDB事务机制

事务机制

1.事务概念

  在对数据的操作的过程中,涉及到一连串的操作,这些操作如果失败,会导致我们的数据部分变化了,部分没变化。这个过程就好比如你去吃早餐,你点完餐了,并且吃完早餐了,没付钱你就跑了,这不符合正常的流程,要保证你是否付钱了,现在有收款语音播报器,能清楚你是否付了钱了。为确保数据的可靠性,采用事务来进行处理。

事务涉及了四个基本特性(ACID):

  1. 原子性(atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
  2. 一致性(consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
  3. 隔离性(isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
  4. 持久性(durability):已被提交的事务对数据库的修改应该是永久性的。

2. 使用事务

  事务和其他支持事务的数据库一样,需要开启和提交事务,MongoDB事务涉及到wirteConcern和readConcern两个属性上

2.1wirteConcern

  `wirteConcern决定了写操作需要落入到多少个节点才算成写入成功

writeConcern的属性有
1.w
w  为0时,对写入数据的正确性不关心,不需要确认
w  为1时, 数据写入到主节点就与客户端进行确认
w  为majority时,数据写入到大多数成员后,再与客户端进行确认
2.  具体的数字
j 为true时,数据写入到主节点持久化后,就与客户端进行确认
3.wtimeout 写入超时时间,防止一直等待的情况,超过超时时间未结束,写入失败
4. 具体的数字
落入到具体数字的节点才与客户端确认

// 包含延迟节点的3节点pss复制集
db.collection.insertOne({name:"李四"},writeConcern:{w:"majority"}})
//  等待延迟节点写入数据后才会响应
db.collection.insertOne({name:"王五"},{writeConcern:{w:3}})
//  超时写入失败
db.collection.insertOne({name:"小明"},{writeConcern:{w:3,wtimeout:3000}})

使用事务的话,大多数情况时使用{w:"majority"}

2.2 readConcern

  读取处于事务中的数据时,需要知道从那读,以及能读取什么样的数据。

  1. readPreferce来解决从哪读的问题

其中选择节点读取的参数有如下:

(1)primary: 只选择主节点,默认模式;
(2)primaryPreferred:优先选择主节点,如果主节点不可用则选择从节点;
(3)secondary:只选择从节点;
(4)secondaryPreferred:优先选择从节点, 如果从节点不可用则选择主节点
(5)nearest:根据客户端对节点的 Ping 值判断节点的远近,选择从最近的节点读取。

具体使用:

# 通过 MongoDB 驱动程序 API
MongoCollection.withReadPreference(ReadPreference readPref)

# Mongo Shell(指定从哪读) 使用readPref简写
db.collection.find().readPref( "secondary" )
db.fsyncLock() 锁定写入
db.fsyncUnLock() 解锁写入

Tag: readPreference的拓展

readPreference只能控制一类节点,而Tag可用于控制一到多个节点,可实现定制服务,某些节点负责在线服务,某个服务负责报表服务。
在这里插入图片描述
具体使用

# 为复制集节点添加标签
conf = rs.conf()
conf.members[1].tags = { purpose: "online"}
conf.members[4].tags = { purpose: "analyse"}
rs.reconfig(conf)

#查询
db.collection.find({}).readPref( "secondary", [ {purpose: "analyse"} ] )
  1. readConcern解决能读取什么样的数据

  决定从哪个节点读取数据后,还需要考虑读取什么样的数据,可选以下参数

(1) available:读取所有可用的数据;
(2) local:读取所有可用且属于当前分片的数据;
(3) majority:读取在大多数节点上提交完成的数据;
(4) inearizable:可线性化读取文档,仅支持从主节点读(线性);
(5) snapshot:读取最近快照中的数据,仅可用于多文档事务(不出现脏读、不可重复读、幻读);

脏读: 读取了事务回滚前的数据或未正确同步的数据

不可重复读: 事务A先读取了一条数据,此时事务B对该数据进行了更新,事务A再次读取了该数据,此时前后读取的数据不匹配

幻读: 事务A读取了N条数据,事务B对这N条数据进行了删除或新增操作,事务A重新读取数据时,数据的条数产生了变化,从而产生了幻读

  1. readConcern读取数据时引发脏读的原因以及解决办法

  写入数据只到达主节点,没有到达其他节点,一旦主节点出现故障,从节点没来得及复制数据,从而导致脏数据的出现。可以设置写入落入大多数节点时再进行写入,虽然消耗了点性能,但保证了数据的不丢失。设置{readConcern: “majority”}。

  1. 安全的实现读写分离

  安全的读写分离,有利于提高效率,并且确保数据安全,其中的措施是将写入和读取都使用majority这个值,确保数据在多个节点都是存在的,并且要选取备节点进行读取。

# 使用writeConcern+readConcern majority来解决
db.collection.insert({oid:101,sku:"kite",q:1},{writeConcern:{w:"majority"}})
db.collection.find({oid:101}).readPref("secondary").readConcern("majority")

5.事务流程

事务内的改变,事务外是无法获取的,直到提交事务后。

var session = db.getMongo().startSession()
# 开启事务
session.startTransaction()

var coll = session.getDatabase("test").getCollection("tx")
#事务内修改 {x:1, y:1}
coll.updateOne({x: 1}, {$set: {y: 1}})
#事务内查询 {x:1}
coll.findOne({x: 1})  //{x:1, y:1}

#事务外查询 {x:1}
db.tx.findOne({x: 1})  //{x:1}

#提交事务
session.commitTransaction()

# 或者回滚事务
session.abortTransaction()


http://www.kler.cn/a/307972.html

相关文章:

  • Linux源码阅读笔记-V4L2框架基础介绍
  • 树形dp总结
  • [前端]NodeJS常见面试题目
  • 软件工程概论项目(二),node.js的配置,npm的使用与vue的安装
  • 文献解读-DNAscope: High accuracy small variant calling using machine learning
  • LeetCode【0031】下一个排列
  • Java重修笔记 第五十六天 坦克大战(六)多线程基础 - 线程同步、死锁
  • 『功能项目』怪物的有限状态机【42】
  • 神经网络卷积层和最大池化
  • 2024 年最佳 Chrome 验证码扩展,解决 reCAPTCHA 问题
  • 小程序——生命周期
  • STM32 移植FATFS时遇到ff_oem2uni函数未定义问题
  • SQLyou基础知识总结(带案例)
  • 3286、穿越网格图的安全路径
  • Elasticsearch之bool查询
  • Vue页面中实现自动播放报警音
  • Python实现Socket.IO的完整指南
  • JavaSE - 易错题集 - 006
  • 学懂C++(六十):C++ 11、C++ 14、C++ 17、C++ 20新特性大总结(万字详解大全)
  • Idea 中的一些配置
  • PointNet++改进策略 :模块改进 | Residual MLP | PointMLP,简化原本复杂的局部几何特征提取器,减少计算同时提高效率
  • 记录近期iOS开发几个报错及解决方案
  • 在线查看 Android 系统源代码 AOSPXRef and AndroidXRef
  • Spring 的循环依赖
  • Git提交类型
  • 3D云渲染农场为何怎么贵?主要消耗成本介绍