【Mongodb】事务
概述
- Mongodb 4.0 支持副本集的多文档事务
- Mongodb 4.2 支持分片集群的多文档事务
单个Server是不支持使用事务,所以要学习事务,需要搭建一个副本集/分片集群
另外需要说明是,单个文档操作是原子操作,而mongodb是文档型数据库,在单个文档上,可以嵌入对象/数组这种格式来维护数据的关系,而不应该使用多个集合来维护数据之间的关系。由于mongodb的这种特性,所以单个文档操作消除了很多需要事务的需求。
搭建副本集
下面以最简单的方式搭建一个副本集
1. 启动多个mongod实例,这里使用cmd命令启动
start "Mongodb Service - 27017" /min mongod --port 27017 --replSet "rs0" --dbpath "F:\Database\Mongodb\Data27017" --logpath "F:\Database\Mongodb\Log\mongod.27017.log"
start "Mongodb Service - 27018" /min mongod --port 27018 --replSet "rs0" --dbpath "F:\Database\Mongodb\Data27018" --logpath "F:\Database\Mongodb\Log\mongod.27018.log"
参数说明
- replSet : 设置副本集名称
- port : 设置端口,因为我是单机,所以只能设置不同端口
- dbpath: 数据文件路径,注:文件夹必须是存在,mongod不会自动创建
- logpath: 日志文件名称,这个不需要提前新建,若不存在mongod会自动创建
2. 连接任意一个实例,这里就选择27017这个默认端口
mongo
3. 启动副本集
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "127.0.0.1:27017" },
{ _id: 1, host: "127.0.0.1:27018" }
]
})
参数说明
- _id : 副本集名称,就是启动实例时指定那个名称
- members : 这个就是所有成员,_id每个成员的标识,整数型[0,255]
返回字段"ok" : 1 代表创建成功
rs.initiate({}),这里除了几个必须的,都是使用默认配置去启动,更多配置参数可以参考replica-configuration
4. 查看当前配置信息
rs.conf()
5. 查看副本集信息
rs.status()
到这,副本集就搭建完成
事务
1. 连接副本集
mongo mongodb://127.0.0.1:27017,127.0.0.1:27018/?replicaSet=rs0
可以直接连接主副本的实例,也可以用这种url形式可以自动连接主副本(推荐使用后者)
2. 准备2条数据
db.balance.insert({ name: "Wilson", balance: 100 }, { writeConcern: { w: "majority", wtimeout: 2000 } });
db.record.insert({ name: "Wilson", change: 100, balance: 100, }, { writeConcern: { w: "majority", wtimeout: 2000 } });
测试正常提交
模拟一个扣钱动作,其中扣款和流水在一个事务里
session = db.getMongo().startSession({ readPreference: { mode: "primary" } });
balanceCol = session.getDatabase("mongo").balance;
recordCol = session.getDatabase("mongo").record;
session.startTransaction({ readConcern: { level: "local" }, writeConcern: { w: "majority" } });
try {
balanceCol.updateOne({ "name": "Wilson" }, { $set: { "balance": 50 } });
recordCol.insertOne({ "name": "Wilson", change: -50, balance: 50 });
} catch (error) {
session.abortTransaction();
}
session.commitTransaction();
session.endSession();
查看余额情况
db.balance.aggregate([
{ $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } },
{ $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } },
]);
结果,可以看到余额扣了,多了一条流水
{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }
测试失败回滚
事务内多增加一个插入不存在的集合操作,让事务报错
session.startTransaction({ readConcern: { level: "local" }, writeConcern: { w: "majority" } });
try {
balanceCol.updateOne({ "name": "Wilson" }, { $set: { "balance": -50 } });
recordCol.insertOne({ "name": "Wilson", change: -50, balance: 0 });
session.getDatabase("mongo").user.insert({ "time": new Date() }); //多增加操作一个不存在的表
} catch (error) {
session.abortTransaction();
throw error;
}
session.commitTransaction();
session.endSession();
返回报错信息,显示事务被中断了
2020-04-15T21:37:05.576+0800 E QUERY [js] uncaught exception: Error: command failed: {
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp(1586957825, 1),
"ok" : 0,
"errmsg" : "Transaction 0 has been aborted.",
"code" : 251,
"codeName" : "NoSuchTransaction",
"$clusterTime" : {
"clusterTime" : Timestamp(1586957825, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:583:17
assert.commandWorked@src/mongo/shell/assert.js:673:16
commitTransaction@src/mongo/shell/session.js:971:17
@(shell):1:1
再查看当前余额情况
db.balance.aggregate([
{ $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } },
{ $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } },
]);
可以看到,余额和流水都没变化。
{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }
参考文章
转发请标明出处:https://www.cnblogs.com/WilsonPan/p/12708710.html
【Mongodb】事务的更多相关文章
- MongoDB - 事务支持
事务简介 事务是数据库中处理的逻辑单元,每个事务中包括一个或多个数据库操作,既可以是读操作,也可以是写操作. ACID 是一个"真正"事务所需要具备的一组属性集合,指的是原子性(A ...
- MongoDB 事务,复制和分片的关系
摘要:本文尝试对Mongo的复制和分布式事务的原理进行描述,在必要的地方,对实现的正确性进行论证,希望能为MongoDB内核爱好者提供一些参考. 1.前言 MongoDB基于wiredTiger提供的 ...
- MongoDB 事务机制
MongoDB 从4.0 版本开始 副本集支持多文档事务,4.2 版本开始分片集群也支持多文档事务.单个集合的单个文档事务 在 1.x 就支持. 以下是跟 mongo 事务相关的一些概念: 1. Wr ...
- SpringBoot整合MongoDB,在多数据源下实现事务回滚。
项目中用到了MongoDB,准备用来存储业务数据,前提是要实现事务,保证数据一致性,MongoDB从4.0开始支持事务,提供了面向复制集的多文档事务特性.能满足在多个操作,文档,集合,数据库之间的事务 ...
- 聊聊MongoDB中连接池、索引、事务
大家好,我是哪吒. 三分钟你将学会: MongoDB连接池的使用方式与常用参数 查询五步走,能活九十九? MongoDB索引与MySQL索引有何异同? MongoDB事务与ACID 什么是聚合框架? ...
- 初窥 MongoDB
最近在研究Nodejs 自然就接触到了MongoDB 这玩意儿有意思 与关系型数据库相比少了很多条条框框 让我情不自禁的想要了解它的所有 MongoDB与Redis同类 属于NoSql的一种,特点 ...
- 使用 Spring Data 进行 MongoDB 4.0 事务处理
使用 Spring Data 进行 MongoDB 4.0 事务处理 原文链接:http://spring.io/blog/2018/06/28/hands-on-mongodb-4-0-transa ...
- 【MongoDB】2019年MongoDB中文社区广州大会,干货满满的分享活动
1 介绍 MongoDB中文社区(mongoing.com)是大中华区获得官方认可的中文社区,11月23日下午,在广州举办了线下用户大会,带给大家一手干货和实践. 2 大会议程 大会组织者对时间的把控 ...
- 分布式缓存 — MongoDB
--- 数据库管理系统 数据库管理系统主要分为俩大类:RDBMS.NOSQL.在个人电脑.大型计算机和主机上应用最广泛的数据库管理系统是关系型DBMS.NoSQL是对不同于传统的关系数据库的数据库管理 ...
- [MongoDB知识体系] 一文全面总结MongoDB知识体系
MongoDB教程 - Mongo知识体系详解 本系列将给大家构建MongoDB全局知识体系.@pdai MongoDB教程 - Mongo知识体系详解 知识体系 学习要点 学习资料 官网资料 入门系 ...
随机推荐
- Java 中的 ==
简介 如果没有重写 equals 方法, 相当于 == 比较, 即比较两个对象的地址是否相等. 如果是基本数据类型, 直接对值进行比较. code /** * Created by lee on 20 ...
- Docker部署RestCloud ETL社区
镜像说明 nriet/restcloud:latest version:1.3.0 os:slim-buster tomcat:基于官方镜像 tomcat:8.5.78-jdk8-openjdk-sl ...
- SciTech-OS-MacOS的CSP(System Integrity Protection)系统正直性保护系统
bash-3.2# csrutil usage: csrutil <command> Modify the System Integrity Protection configuratio ...
- 深度技术解决win11居中任务栏图标变小的方法
相信很多深度技术的用户都已经安装了win11系统,而win11系统带来的全新界面包括任务栏也进行了改变,有不少的用户使用的时候都感觉任务栏的图标太大了不习惯,为此我们就给大家带来把win11系统居中任 ...
- 04Java基础语法之包机制
包机制 为了更好的组织类,Java提供了包机制,用于区别类名的命名空间. 包语句的语法格式为: package pkg1[. pkg2[. pkg3...]]; 一般会使用公司域名倒置作为包名: 例如 ...
- 数据库的<> 比较运算
数据库的<> 比较运算的等于!= where name <> '张三' 会把NULL的值对应的记录排除掉,所以不包含null和NULL的记录:所以只有''和'李四'才符合条件, ...
- java 泛型 反射 动态代理 注解
https://www.cnblogs.com/20183544-wangzhengshuai/p/16033270.html Java 高级特性有挺多,但是这几个一直没搞太通透,只会简单用用,为什么 ...
- 如何在uni-app 平台快速实现一对一音视频通话应用
"一套代码,多端运行"是很多开发团队的梦想.ZEGO SDK基于uni-app跨平台框架支持iOS.Android.Windows.macOS.HarmonyOS.Web.小程序并 ...
- NativeExcel使用
var Book: IXLSWorkbook; ws: IXLSWorksheet; begin Book := TXLSWorkbook.Create; //建立NativeExcel ws := ...
- Solidity学习之代理合约
什么是代理合约 代理合约针对的是链上合约一经部署无法修改的问题,通过增加一层代理合约,就可以在不修改代理合约代码和地址的前提下,对实际执行的逻辑进行调整,满足了合约升级的需要. 实现逻辑 代理模式将状 ...