如果两个组件在同一个进程中(同一个VM中、同一个主机内)执行,这种模式也许没有必要,但即使这样,它也可能很有趣,可以将其用于解耦和可维护性,或作为将这些组件分离到不同的微服务中工作做准备,也许在未来的某个时候我们能平滑升级到微服务。这一切都取决于我们目前的需求,未来的需求。
三。 事件溯源
我们假设一个实体处于一种初始状态。作为一个实体,它有自己的身份,代表在现实世界中一个特定的事情,应用程序将其建模为实体。在其生命周期中,实体数据会发生变化,并且传统上实体的当前状态被简单地作为表的一行记录存储在数据库中。
(1)事务日志
这在大多数情况下都是可以的,但如果我们需要知道实体是如何达到当前这个状态,即我们想知道我们的银行账户的贷方和借记发生的每笔金额,才能知道当前账户的余额来历,这在传统只保存当前状态的方式下是不可能实现的,因为我们只存储当前状态!每次都是新的余额状态覆盖了之前的状态,比如当前余额是10,覆盖了之前余额90,至于账户余额怎么剩余10元呢?如果数据库不保存往来明细,你可能认为银行系统出问题了。
存储实体发生的事件,而不是存储Entity状态,我们专注于存储实体状态更改并从这些更改中计算实体状态。每个状态变化是一个事件,存储在事件流中(即RDBMS中的一个表)。当我们需要实体的当前状态时,我们从事件流中的所有事件中计算出它。
事件存储成为真相的主要来源,系统状态纯粹源于它。对于程序员来说,最好的例子是版本控制系统。所有提交的日志是事件存储,源树的工作副本是系统状态。---2010年Greg Young, CQRS文件
(2)如何删除?
如果我们发现一个状态改变(事件)是一个错误,我们不能简单地删除该事件,因为这会改变状态更改历史记录,这将违反整个事情溯源的想法。相反,我们在事件流中创建一个事件,以反转我们要删除的事件。这个过程称为反转事务,不仅使实体返回到所需的状态,而且留下了一个跟踪,显示对象在给定时间点处于该状态。
不删除数据也具有架构优势。存储系统成为只添加一个体系结构,众所周知,仅附加体系结构比更新架构更容易分发,因为要处理的锁少得多。---2010年Greg Young, CQRS文件
(3)快照
但是,当事件流中有许多事件时,计算实体状态将是非常昂贵的,因此为了避免出现这种情况。每X个事件我们将在该时刻创建一个实体状态的快照。这样,当我们需要实体状态时,我们只需要计算它到最后一个快照。我们甚至可以永久保存更新实体的快照,这样我们平衡了两种世界(只保存状态和只保存事件)。