《MongoDB高手课》学习记录(第十九天)

第十九天

今天要学习的章节是《22 | 事务开发:多文档事务》,主要讲解多文档事务管理。shell

说明

  • MongoDB 在 4.2 开始全面支持了多文档事务.
  • 对事务的使用原则应该是:能不用尽可能不用。
  • 经过合理地设计文档模型,能够规避绝大部分使用事务的必要性
  • 为何?事务 = 锁,节点协调,额外开销,性能影响

MongoDB ACID 多文档事务支持

  • Atomocity(原子性)
    单表单文档 : 1.x 就支持,文档中的字段要么多更新,要么不更新,不会出现一部分更新。
    复制集多表多行:4.0开始支持
    分片集群多表多行:4.2开始支持
  • Consistency(一致性)
    writeConcern, readConcern (3.2版本开始支持)
  • Isolation(隔离性)
    readConcern (3.2版本开始支持)
  • Durability(持久性)
    Journal and Replication

事务的隔离级别

  • 事务完成前,事务外的操做对该事务所作的修改不可访问
  • 若是事务内使用 {readConcern: “snapshot”},则能够达到可重复读Repeatable Read

事务隔离

即事务内的变化没提交前不影响事务外的数据数据库

db.tx.insertMany([{ x: 1 }, { x: 2 }]);
var session = db.getMongo().startSession();
session.startTransaction();
var coll = session.getDatabase('test').getCollection("tx");
coll.updateOne({x: 1}, {$set: {y: 1}});
coll.findOne({x: 1}); // 返回 {x:1, y:1}
db.tx.findOne({x: 1}); // 返回 {x:1}
session.abortTransaction()

可重复读

事务外虽然数据已经更新,在事务内结束前,读取的数据一致是相同的。session

var session = db.getMongo().startSession();
session.startTransaction({
readConcern: {level: "snapshot"},
writeConcern: {w: "majority"}});
var coll = session.getDatabase('test').getCollection("tx");
coll.findOne({x: 1}); // 返回:{x: 1}
db.tx.updateOne({x: 1}, {$set: {y: 1}});
db.tx.findOne({x: 1}); // 返回:{x: 1, y: 1}
coll.findOne({x: 1}); // 返回:{x: 1}
session.abortTransaction();

事务写机制

MongoDB 的事务错误处理机制不一样于关系数据库:性能

  • 当一个事务开始后,若是事务要修改的文档在事务外部被修改过,则事务修改这个文档时会触发 Abort 错误,由于此时的修改冲突了;
  • 这种状况下,只须要简单地重作事务,也就是把事务停止了,从新开始;
  • 若是一个事务已经开始修改一个文档,在事务之外尝试修改同一个文档,则事务之外的修改会等待事务完成才能继续进行。

实验:写冲突

var session = db.getMongo().startSession();
session.startTransaction({ readConcern: {level: "snapshot"},
writeConcern: {w: "majority"}});
var coll = session.getDatabase('test').getCollection("tx");

继续使用上个实验的tx集合,开两个 mongo shell 均执行下述语句
窗口1:
coll.updateOne({x: 1}, {$set: {y: 1}}); // 正常结束
窗口2:
coll.updateOne({x: 1}, {$set: {y: 2}}); // 异常 – 解决方案:重启事务学习

实验:写冲突 (续)

窗口1:第一个事务,正常提交
coll.updateOne({x: 1}, {$set: {y: 1}});
窗口2:另外一个事务更新同一条数据,异常
coll.updateOne({x: 1}, {$set: {y: 2}});
窗口3:事务外更新,需等待
db.tx.updateOne({x: 1}, {$set: {y: 3}})设计

注意事项

  • 能够实现和关系型数据库相似的事务场景
  • 必须使用与 MongoDB 4.2 兼容的驱动;
  • 事务默认必须在 60 秒(可调)内完成,不然将被取消;
  • 涉及事务的分片不能使用仲裁节点;
  • 事务会影响 chunk 迁移效率。正在迁移的 chunk 也可能形成事务提交失败(重试便可);
  • 多文档事务中的读操做必须使用主节点读;
  • readConcern 只应该在事务级别设置,不能设置在每次读写操做上。
相关文章
相关标签/搜索