我正试图在MongoDB中找到这种情况的准确答案,但无法从任何来源获得令人满意的答案。
许多熟悉数据库培训示例的人,只是在万一有人需要的情况下进行解释。这是DB2中的示例。 Person-1的帐户余额为$ 100.00。 Person-1前往柜员/ ATM存入$ 20.00到他的帐户,余额更新在系统中执行以下步骤。为了更好地理解,我提供了活动时间。
Person-1的朋友在9:00:00:001在互联网上转移了30美元 如果系统此时读取Person-1的帐户以进行更新,则系统会将$ 30加到100,最终余额将变为$ 130或$ 120,这取决于以后发生的余额更新。但余额应为$ 150。
为避免该错误,DB2在步骤1的上方记录了更新锁定,因此Internet传输事务在步骤3完成之前无法读取余额以进行更新(步骤3自动释放锁定)。此外,只要其他线程不读取更新内容,其他线程就可以随时读取记录。
注意:在这种情况下,DB2仅锁定person-1的帐户记录,而不锁定整个表(集合),因为其他帐户更新可以同时继续。
有人可以解释一下如何在mongoDB中实现吗?我听到有人说在文档中使用标记并通过应用程序进行控制,但这是不准确的,在上述情况下也可能导致失去平衡。
谢谢 纳尔
答案 0 :(得分:0)
有人可以解释一下在mongoDB中是如何实现的吗?
这里没有多少要打开的物品,但让我们从基本的MongoDB multi-document Transactions开始。
如果在事务会话内部执行更新操作,则第二个更新操作将被阻止,直到第一个事务已提交,中止或到期为止。在MDBW18: How and When to Use Multi-Document Distributed Transactions
上查看有关此行为的更多信息例如(基于MongoDB v4.0.3),如果您具有以下文档:
{"person": "one", "balance": NumberDecimal(100)}
具有如下更新操作:
s1 = Mongo().startSession() ;
sessionFoo = s1.getDatabase("databaseName").collectionName;
s1.startTransaction();
var result = sessionFoo.update({"person":"one"}, {"$set":{"balance":120}});
// ...
s1.commitTransaction();
如果在commitTransaction
之前发生了另一项更新操作(与上面类似),它将收到TransientTransactionError
。错误输出示例:
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp(1540175676, 1),
"ok" : 0,
"errmsg" : "Unable to acquire lock '{7817449386782089629: Database, 899920359141007773}' within a max lock request timeout of '5ms' milliseconds.",
"code" : 24,
"codeName" : "LockTimeout",
在9:00:02:001,将$ 120更改为Person-1在DB2中的帐户记录
通常,您不会更新为某个值,而是对该值执行事件增量($inc operator)。因此,而不是:
var result = sessionFoo.update({"person":"one"}, {"$set":{"balance":120}});
应该是:
var result = sessionFoo.update({"person":"one"}, {"$inc":{"balance":20}});
要进一步扩展此功能(通常用于财务相关记录),您想捕获事件而不是状态。另请参见Even Sourcing。例如,而不是下面的示例:
t1: balance 100
t2: balance 120
t3: balance 150
t4: balance 70
其中balance
代表时间t
的平衡状态。可能是诸如以下事件:
t1: balance 100
t2: balance +20
t3: balance +30
t4: balance -80
这样可以保存一个时间点的历史记录。即从48小时前开始重播交易。
在这种情况下,DB2仅锁定person-1的帐户记录,而不锁定整个表(集合),因为其他帐户更新可以同时继续
请注意,在MongoDB中,对单个文档的操作是原子的(即使没有事务功能)。这是因为您可以使用embedded文档和数组来捕获单个文档结构中数据之间的关系,而不是在多个文档和集合之间进行规范化,这种单文档原子性避免了很多实际使用中对多文档事务的需求案件。另请参见MongoDB Data Model Design。