DDD聚合:乐观并发 -James Hickey


当系统的多个用户尝试在“相同”时间对同一块数据进行操作时,会发生什么情况?谁赢?谁输了?本文将说明如何解决此类问题!
协作领域是可以同时由多个用户/客户端更改资源的领域,这要求对我们的业务逻辑进行更智能的处理。
解决此问题的最流行方法之一是使用并发控件。换句话说,当数据不同步时,一种阻止这些并发写入数据库的方法。

悲观并发
一种方法是使用悲观并发。这是当我们锁定整个资源并且在任何时候仅允许一个操作被访问时。
有点像打开excel时,现在网络驱动器上没有其他人可以修改它了。
但是,这会导致性能不佳,并且从某种意义上讲是天真的,因为我们只是“蛮力”锁定所有内容。

乐观并发
乐观并发在某种程度上更加智能和灵活。它还允许一些有趣的故障模式。
通过允许每个操作获取数据存储区的当前版本来工作。它可能是关系数据库,文档或事件溯源。没关系
然后,只要有聚合写回,就针对数据存储测试其版本,如果版本不同步(即在执行此操作时其他人已将其写入存储),那么我们将使操作失败。
这提供了一种有趣的故障模式,在该模式下,可以仅重试失败的操作。只要数据存储中有更新,它的操作仍然有意义。

如何实施?
例如,事件存储具有此内置功能
例如,.NET客户端中的一种写入方法如下所示:

Task<WriteResult> AppendToStreamAsync(string stream, long expectedVersion, params EventData[] events)

第二个参数是告诉事件存储您期望的版本的位置。如果不是那个版本,如上面的示例,那么事件存储将告诉您。
在关系数据库中,您可以执行以下操作:

UPDATE sometable T
SET something = @someDataParam
WHERE T.RowVersion = @expectedRowVersionParam

根据您的数据库引擎,这将返回受影响的行数。如果没有影响,那么您就知道在另一个操作“事务失败”之前,另一个操作已写入数据存储。