MongoDB4.0事务采坑
发布于 7 年前 作者 MedusaLeee 8312 次浏览 来自 分享

详细demo地址

MongoDB4.0事务采坑

如有错误,还请指正。

版本

MongoDB server version: 4.0.0

限制

MongoDB有三种部署方式,分别是单实例、副本集和分布式部署。目前只有副本集支持事务, 所以只能现部署副本集的MongoDB集群了。

部署MongoDB副本集集群

在我的Mac已经安装3.x版本,为了不影响开发,我们使用docker部署。 部署示例

MongoDB Nodejs Driver Demo

Nodejs mongodb库的版本 > 3.1.0

代码

const {MongoClient} = require('mongodb');
const uri = 'mongodb://192.168.31.93:27017,192.168.31.93:27018/mongo-tx';
const oneTableTest = async () => {
 const client = await MongoClient.connect(uri, {useNewUrlParser: true, replicaSet: 'rs2'});
 const db = client.db();
 // 删除表内老数据
 await db.collection('order').deleteMany({});
 // 成功完成一个事务
 // 开启事务
 let session = client.startSession();
 await session.startTransaction();
 // 插入一条新数据
 await db.collection('order').insert({
 name: 'order1',
 total: 50
 }, {session});
 await session.commitTransaction();
 session.endSession();
 let count = await db.collection('order').countDocuments();
 console.log(`oneTableTest-现在order表中有数据${count}条`);
 // 事务回滚
 // 开启事务
 session = client.startSession();
 await session.startTransaction();
 try {
 // 插入一个正确的订单
 await db.collection('order').insert({
 name: 'order2',
 total: 100
 }, {session}); // 每次操作都得带上 session
 count = await db.collection('order').countDocuments();
 console.log(`oneTableTest-现在order表中有数据${count}条`);
 // 抛出一个异常
 throw new Error('订单异常');
 } catch (e) {
 // 有异常,终止事务
 console.log('异常,回滚事务');
 // 执行完成后,发现name为order2的订单 没有插入数据库
 await session.abortTransaction();
 session.endSession();
 count = await db.collection('order').countDocuments();
 console.log(`oneTableTest-现在order表中有数据${count}条`);
 }
};
const multiTableTest = async () => {
 const client = await MongoClient.connect(uri, {useNewUrlParser: true, replicaSet: 'rs2'});
 const db = client.db();
 // 删除表内老数据
 await db.collection('order').deleteMany({});
 await db.collection('product').deleteMany({});
 // 插入一条新数据
 await db.collection('order').insert({
 name: 'order1',
 total: 50
 });
 await db.collection('product').insert({
 name: 'product1',
 price: 50
 });
 let orderCount = await db.collection('order').countDocuments();
 console.log(`multiTableTest-现在order表中有数据${orderCount}条`);
 let productCount = await db.collection('product').countDocuments();
 console.log(`multiTableTest-现在product表中有数据${productCount}条`);
 // 开启事务
 const session = client.startSession();
 await session.startTransaction();
 try {
 // 插入一个正确的订单
 await db.collection('order').insert({
 name: 'order2',
 total: 100
 }, {session}); // 每次操作都得带上 session
 // 插入一个正确的商品
 await db.collection('product').insert({
 name: 'product2',
 price: 100
 }, {session}); // 每次操作都得带上 session
 orderCount = await db.collection('order').countDocuments();
 console.log(`multiTableTest-现在order表中有数据${orderCount}条`);
 productCount = await db.collection('product').countDocuments();
 console.log(`multiTableTest-现在product表中有数据${productCount}条`);
 // 抛出一个异常
 throw new Error('多表异常');
 } catch (e) {
 // 有异常,终止事务
 console.log('多表异常,回滚事务');
 // 执行完成后,发现name为order2的订单,name为product2的商品都没有插入数据库
 await session.abortTransaction();
 session.endSession();
 orderCount = await db.collection('order').countDocuments();
 console.log(`multiTableTest-现在order表中有数据${orderCount}条`);
 productCount = await db.collection('product').countDocuments();
 console.log(`multiTableTest-现在product表中有数据${productCount}条`);
 }
};
const main = async () => {
 await oneTableTest();
 await multiTableTest();
};
main().then();

结果

mongo-driver-result.png

由结果看多表单表事务都是支持的,且事务未结束前,出于事务中的操作是不会真实入库的。

Mongoose Demo

mongoose库的版本 > 5.2.0

代码

const mongoose = require('mongoose');
const uri = 'mongodb://192.168.31.93:27017,192.168.31.93:27018/mongo-tx';
const oneTableTest = async () => {
 await mongoose.connect(uri, { useNewUrlParser: true, replicaSet: 'rs2' });
 const Order = mongoose.model('Order', new mongoose.Schema({
 name: String,
 total: Number
 }));
 await Order.remove({});
 let count = await Order.countDocuments({});
 console.log(`oneTableTest-现在order表中有数据${count}条`);
 // 正常事务
 let session = await mongoose.startSession();
 await session.startTransaction();
 await Order.create({
 name: 'order3',
 total: 150
 });
 await session.commitTransaction();
 session.endSession();
 count = await Order.countDocuments({});
 console.log(`oneTableTest-现在order表中有数据${count}条`);
 // 事务回滚
 session = await mongoose.startSession();
 await session.startTransaction();
 try {
 // 这种写法不行 create方法不接收 options参数,如果要接收options参数,第一参数必须为Array
 // 见文档 http://mongoosejs.com/docs/api.html#create_create
 // await Order.create({
 // name: 'order4',
 // total: 200
 // }, {session});
 // 这种写法可以
 // await Order({
 // name: 'order4',
 // total: 200
 // }).save({session});
 // 这种写法也可以
 await Order.create([{
 name: 'order4',
 total: 200
 }], {session});
 count = await Order.countDocuments({});
 console.log(`oneTableTest-现在order表中有数据${count}条`);
 // 抛出一个异常
 throw new Error('订单异常');
 } catch (e) {
 // 有异常,终止事务
 console.log('异常,回滚事务');
 await session.abortTransaction();
 session.endSession();
 count = await Order.countDocuments();
 console.log(`oneTableTest-现在order表中有数据${count}条`);
 }
};
oneTableTest().then();

结果

此例子没有测试多表,结果和上面的测试一样,只是不同的驱动。

mongoose-result.png

11 回复

事物 -> 事务

@alsotang 您说的对,只怪语文是体育老师教的,哈哈,一会就改

来自酷炫的 CNodeMD

可以的 4.0终于来了

现在官方给出的文档,没有给出mongodb4.0 nodejs drive的文档啊 image.png

那么问题来了,在哪看文档呢?

而且 npm search搜出来的 nodejs drive 大于3.1 版本的只有一个 3.1.1 ,也是是说只有这一个4.0的版本可用呢? image.png

用到事务还不如上pgsql了。。。

@jjeejj Nodejs mongodb 驱动的版本 > 3.1.0就可以

来自酷炫的 CNodeMD

@waitingsong 您说的是,有总比没有好

来自酷炫的 CNodeMD

楼主研究过mongodb的事务隔离级别吗? snapshot感觉好复杂。

来自酷炫的 CNodeMD

@waitingsong mongodb的好处业务建模快 结构灵活 所想即所得 加了事务如虎添翼

@phper-chen 比数据结构,mongo和pg不是一个级别的吧。

回到顶部

AltStyle によって変換されたページ (->オリジナル) /