接上期,MongoDB 的事务操作已经操作了,但细节和参数并没有弄清楚,通过mongodb 的事务操作主要分为以下几个部分
1 Session.startTransaction
2 Session.commitTransaction
3 Session.abortTransaction
简单的回顾一下,MONGODB 的事务,当一个事务中所有对数据的更改commit 后,外部是可以读取 commit 后的数据,在commit前这些数据在事务之外都不可见。事务中多个操作,其中之一失败,则事务整体失败,则在失败事务之前的操作全部丢弃。这里暂且认为MONGODB 的事务是 READ COMMITED 的方式对我们呈现的。
在昨天的示例里, mongodb 开始一个事务
session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
需要注意的参数 readConcern 和 writeConcern
readConcern 可以选择 snapshot local majority
这三者的不同点 snapshot 主要针对多文档的事务提交,在readConcern选择了snapshot后,保证了多文档提交后,读取数据是从大多数节点,保证数据的准确性,事务提交时 startTransaction 的readConcern 必须要选择 snapshot, writeConcern 则也必须选择 marjority 保证写入的事务不会在回滚,确定在大多数节点已经落实。
对于事务的操作总,数据库中config, admin, local collections 是无效的,system.开头的 collection 也是无效的,对于事务的操作仅仅限于客户自定义的collections。游标如果是在事务内发生的,则只能在事务内部调用,同理事务内部不能调用外部的游标。
在事务内也禁止使用 DDL 操作,如创建一个索引,一个collection ,一个database ,创建账号 修改密码 等操作,事务内支持 CRUD 的操作。
事务的操作中,如果事务中的一个单独的操作失败了,是不会在进行重试,在事务commit 的阶段提交如果失败了,MONGODB 是会进行重试的。
那么一个完整的事务的提交并且包含重试和报错的程序怎么来操作
下面是一些操作步骤,
1 登陆mongoshell 通过mongosh 登陆 (不知道什么是mongosh 可以去官网看一下)
2 两个
function runTransactionWithRetry(txnFunc, session) {
while (true) {
try {
txnFunc(session); // performs transaction
break;
} catch (error) {
if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError") ) {
print("TransientTransactionError, retrying transaction ...");
continue;
} else {
throw error;
}
}
}
}
function commitWithRetry(session) {
while (true) {
try {
session.commitTransaction();
print("Transaction committed.");
break;
} catch (error) {
if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
print("UnknownTransactionCommitResult, retrying commit operation ...");
continue;
} else {
print("Error during commit ...");
throw error;
}
}
}
}
事务函数
function updateEmployeeInfo(session) {
employeesCollection = session.getDatabase("test").test;
eventsCollection = session.getDatabase("test").test1;
session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
try{
employeesCollection.insertOne( { employee: 3 }, { $set: { status: "Inactive" } } );
eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
} catch (error) {
print("Caught exception during transaction, aborting.");
session.abortTransaction();
throw error;
}
commitWithRetry(session);
——————————————————————————————
执行MONGODB 事务
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
try{
runTransactionWithRetry(updateEmployeeInfo, session);
} catch (error) {
} finally {
session.endSession();
}
执行后的结果。
具体MONGODB 在事务中可以操作的列表命令 在下方网址可以查询详细信息
Transactions and Operations — MongoDB Manual
后面还会关注MONGODB 的事务,以及一些案例。