事件溯源需要多少数据库或 table?

How many database or table needed for Event sourcing?

我正在尝试使用事件溯源、ddd 和 cqrs。 我无法理解我必须创建两个数据库(或 table)(1-json 2-normalize 数据库)或一个数据库(仅 json) 而且,如果我创建了两个数据库(或 table),我是否必须在一个事务中将数据库中的数据(json 和规范化)保存为原子数据? 最好的问候

DDD

我们在此假设您完全理解 DDD 的使用及其含义。具体与事件溯源相关,它是定义聚合边界和成为它们状态的事件的问题。

CQRS

我们再次假设您完全理解其中的含义。 CQRS 仅 允许 您在垂直切片(即从 UI 到数据库)中编写代码,以将“命令”与处理“查询”的代码分开。就这样。虽然您确实可以更进一步,通过将数据存储在甚至可能位于不同数据库中的“读取模型”中,更不用说 table,这不是实施 CQRS 的要求。

由于 CQRS 与事件溯源相关 - 它非常适合,因为您倾向于在事件溯源中使用的数据模型不利于复杂查询。它通常仅限于“通过它的 ID 获取聚合”。因此,使用“投影”以更适合查询和加载到 UI 的其他方式存储数据是典型的方法。

事件溯源

如果您以聚合处理的每个命令(即用户执行的每个use-case/task)生成一个或多个事件的方式实现域模型,那么事件源就是您的原则根据聚合的 ID 以仅追加的方式存储这些事件列表,而不是在成功处理命令后存储聚合的快照。

要从事件存储中加载一个聚合,您需要加载它之前的所有事件,并在聚合对象的内存中重播它们,而不是将单个 row/document 作为 snapshot/memento 加载.

因此,文档数据库是事件存储的绝佳选择,因为单个文档代表给定聚合的事件流。但是,如果您想将事件流存储在 SQL 中,那很好,但您可以将其存储在两个 table 中:

create table Aggregate (Id int not null...);
create table AggregateEvent(AggregateId int not null FK..., Version int not null, eventBody nvarchar(max));

实际的事件主体通常是事件本身,序列化为文本格式,如 JSON。

投影和读取存储

如果您获取通过聚合处理命令生成的事件,并编写通过写入单独的数据存储(SQL、预先计算的 ViewModel 等)来使用它们的代码,那么您可以称之为“投影”。它是将一种形状的数据“投影”到适合不同目的的另一种形状。结果是一个“读取存储”,然后您可以根据需要查询它。

I can't understand that I have to create two database (or table) ( 1-json 2-normalize database) or one database (just json)

只用一个事件存储就可以解决问题。

然而,“过得去”并不一定令人愉快。通常,事件存储非常擅长“追加新信息”,但不是特别擅长“查询”。因此,通常的答案是部署将信息从事件存储复制到具有更好查询支持的东西的过程。

I have to save data in databases (json and normalize) as atomic in one transaction or not?

常见的模式是仅更新事件存储,然后调用流程将信息从事件存储复制到您的查询支持。当然,这也意味着您的查询可能最终会显示 old/out 的日期信息(这里是您五分钟前的问题的答案)。

如果您将查询友好型数据模型存储在事件存储中(例如,同一关系数据库中的表),那么您可以至少安排一些对查询友好型模型的更新与事件。

换句话说,您需要权衡取舍,而不是随处使用的单一千篇一律的模式。