最佳事件采购数据库策略

best event sourcing db strategy

我想设置一个小型事件源库。 网上看了几个教程,到此为止都明白了。

唯一的问题是,在这些不同的教程中,有两种不同的数据库策略,但没有任何评论为什么他们使用他们使用的那个。

所以,我想征求一下您的意见。 重要的是,为什么您更喜欢您选择的解决方案。

  1. 解决方案是为每个事件创建一个 table 的数据库结构。

  2. 解决方案是只创建一个通用 table 的数据库结构,并将事件作为序列化字符串保存到一列。

在这两种情况下,我都不确定他们是如何处理事件变化的,也许他们会创建一个全新的。

亲切的问候

我构建了自己的事件源库并选择了选项 2,原因如下。

  • 您通过聚合 ID 而非事件类型查询事件流。
  • 如果事件都在不同的表中,按顺序重现事件会很痛苦
  • 这会让升级事件有点痛苦

有人说您可以将事件存储在每个聚合上,但这取决于项目的要求。

我确实有一些关于如何使用事件流的帖子,您可能会觉得有用。

Solution is the db structure where you create only one generic table, and save the events as serialized string to one column

这是迄今为止最好的方法,因为重播事件更简单。现在我对事件溯源的两分钱:这是一个很好的模式,但你应该小心,因为并非一切都像看起来那么简单。在我正在处理的系统中,我们保存了每个聚合的事件流,但我们仍然有一组规范化表,因为我们无法接受为了获得对象的最新状态,我们必须 运行 所有事件(快照有帮助但不是完美的解决方案)。所以是的,事件溯源是一个很好的模式,它为您提供了实体的完整版本控制和完整的审计日志,它应该仅用于此目的,而不是作为一组规范化表的替代品,但这只是我的两个分.

我认为最好的解决方案是 #2。如果您使用像 mysql.

这样的事务数据库,甚至可以同时保存当前状态和相关事件

我真的不喜欢并推荐解决方案 #1

如果您对 #1 的关注是关于事件 versioning/upgrading;然后为每个新更改声明一个新的 class。不要太懒惰;或者沉迷于重用。让订阅者知道变化;给他们活动版本。

如果您对 #1 的担忧与 querying/interpreting 事件有关;然后您可以随时轻松地将事件推送到 nosqldb 或 eventstore(从原始数据库)。

还有;我用于事件采购库的模式是这样的:

public interface IUserCreated : IEventModel
{

}

public class UserCreatedV1 : IUserCreated
{
    public string Email { get; set; }
    public string Password { get; set; }
}

public class UserCreatedV2 : IUserCreated
{
    // Fullname added to user creation. Wrt issue: OA-143

    public string Email { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class EventRecord<T> where T : IEventModel
{
    public string SessionId { get; set; } // Can be set in emitter.
    public string RequestId { get; set; } // Can be set in emitter.
    public DateTime CreatedDate { get; set; } // Can be set in emitter.
    public string EventName { get; set; } // Extract from class or interface name.
    public string EventVersion { get; set; } // Extract from class name
    public T EventModel { get; set; } // Can be set in emitter.
}

public interface IEventModel { }

所以;使事件版本控制和升级明确;在域和代码库中。在部署新事件的来源之前,在订阅者中实施新事件的处理。和;如果不需要,不允许直接使用来自外部订阅者的域事件;放置一个集成层或类似的东西。

希望我的想法对你有用。

我读到了一种事件溯源方法,它包括:

  1. 有两个 table:聚合和事件;
  2. 根据您的用例:

    一个。在聚合 table 上创建和注册,生成 ID、版本 = 0 和事件类型,并在事件 table;

    上创建事件

    b。按 ID 或事件类型从聚合 table、事件中检索,应用业务案例,然后更新聚合 table(版本和事件类型),然后在事件 table.[=10 上创建事件=]

尽管我使用这种方法更新了聚合 table 上的某些字段,但它将事件 table 保留为仅附加并提高了性能,因为您拥有聚合的最新版本 table .

我会选择 #2,如果您真的想要一种通过事件类型进行搜索的有效方式,我会在该列上添加一个索引。

以下是访问本案所涉及主体数据的两种策略。 1) 当前状态和 2) 事件排序。 使用当前状态,我们处理事件但只保留主题的最后状态。 通过事件排序,我们保留事件并通过在每次需要状态时处理事件来重建当前状态。 事件排序更可靠,因为我们可以跟踪导致当前状态发生的所有事情,但它绝对效率不高。保留中间状态(快照)而不仅仅是最后一个状态是一种常识,以避免一直重新处理所有事件。现在我们拥有可靠性和性能。

在加密货币中有事件排序和本地快照——名称中的本地是因为区块链是分布式的,数据是复制的。