NoSQL数据库不会,一般,提供保证完全成功或失败的RDBMS样式的事务。 (我知道有些人会这样做,但我有兴趣探索他们不这样做的情况。)然而,NoSQL提供商很快指出传统RDBMS数据库中需要事务的行为可以在原子NoSQL操作中完成(即单文档写入)。例如,这是CouchDB approach to doing bank transactions - 而不是减少一个余额并增加另一个(在RDBMS中的事务中写入两个),您编写一个描述传输的新文档。
但是,在RDBMS事务中进行此类传输可能涉及三个操作:
当处理两笔付款试图从一个只能负担一个或另一个的账户中获取资金时,我们如何在NoSQL环境中管理这个并确保我们最终不会透支?当两个操作尝试更新同一文档时,NoSQL数据库通常具有检测和防止写冲突的机制。但是,由于编写文档描述转移的方法意味着编写新文档,因此不会检测到同时发生的两笔付款。
这里有一个明显的问题,就是使用代码锁来阻止两个付款在应用程序级别同时启动,但我感兴趣的是是否存在“合理”锁定 - 检查值然后改变它以防止并发操作将值置于无效状态的自由方法?
我已经提出了几种实现这一目标的方法,但由于某种原因两者都令人不快 - 我对是否有一个我错过的更简洁的解决方案感兴趣。为了一个有用的比喻,我将在余额转移方面对它们进行描述。假设Alice试图同时向Bob和Charlie支付费用,但只能支付其中一个。
简单地将两笔付款都通过。每次付款后,检查Alice是否未透支。这里的问题是,这两笔付款都有可能发现透支并退出。如果他们都放弃了这一点,那么当人们可以拥有时,他们都不会成功。如果他们在退出后再次检查余额,他们可能都会看到有足够的钱再次尝试,他们可以这样做。循环继续。这可以通过随机的退避延迟来解决(最终),但这会给应用程序带来负担,以相对复杂的方式管理重试,并且还可能留下很长的失败付款记录。
也有可能的是,如果有人将资金转移到 Alice的帐户中,那么这两种付款实际上都会成功。爱丽丝将会非常短暂地透支,但现在却处于黑暗状态。这可能是也可能是不可接受的。
这样我们就可以使用写入冲突检测来强制一次付款再试一次。但是,我们附加的文件会变得非常快,而且我们也放弃了支付索引的能力。
所有人都告诉我,供应商声称,对于像这样的应用程序,RDBMS可能仍然是最好的工具。