【问题标题】:Relational database schema for event sourcing用于事件溯源的关系数据库模式
【发布时间】:2014-06-19 18:38:39
【问题描述】:

我正在尝试将域事件存储在 postgres 数据库中。很多事情我都不确定,也不想以后重新设计这个结构,所以我正在寻求有事件溯源经验的人的指导。我目前有下表:

domain events
    version - or event id, integer sequence, helps to maintain order by replays
    type - event type, probably classname with namespace
    aggregate - aggregate id, probably random string for each aggregate
    timestamp - when the event occured
    promoter - the promoter of the event, probably user id
    details - json encoded data about the properties

我不确定:

  1. 我应该存储域事件的启动子吗?
    它可能有助于找到因安全漏洞而受损的帐户,但 我不知道要存储什么,例如通过 CRONjob。
  2. 我应该以什么格式存储事件类型?
    我应该添加一个包含事件类型的表,还是类名就足够了?
    我应该添加事件组吗?
  3. 我对有界上下文的定义感到困惑。据我所知,每个聚合都可以有多个有界上下文,因此我可以在多个模块中使用单个聚合的不同方面。这听起来不错,因为例如帐户可以与许多事物相关,包括身份验证、授权、用户配置文件、用户帖子、用户合同等等...
    我不确定,域事件可以有多个有界上下文,或者只有一个,所以我也应该存储事件上下文吗? (对于我想重播与单个上下文相关的事件的情况)
    如何在一个聚合类中实现这么多属性,我应该使用某种组合吗?

【问题讨论】:

  • 第 41 页 cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf 。仅供参考,我对事件溯源不是很有经验
  • 如果您使用的是 .net,则可以使用 NEventStore 库为您执行此操作。如果没有,您可以尝试查看由 Greg Young 构建的 GetEventStore
  • 谢谢,我会阅读它们,我可能会找到一些问题的答案。

标签: postgresql domain-driven-design cqrs event-sourcing bounded-contexts


【解决方案1】:

1.我应该存储领域事件的发起人吗?

我认为如果您将启动器存储为事件有效负载的一部分而不是元数据,它会更加灵活。安全问题应在域外处理。并非每个事件都是由用户提出的,尽管您可以为他们制作一个假的(CronJob 的系统管理员)。

例如:

ManualPaymentMadeEvent { //store this object as details in your schema
    amount,
    by_user//In this case, developers can determine whether store the promoter case by case
}

2.我应该以什么格式存储事件类型?
我应该添加一个包含事件类型的表,还是类名就足够了? 我应该添加事件组吗?

我认为类名就足够了。添加另一个表会使事件读取复杂化(通过连接表),我认为它只会在类名被重命名时增加价值(更新事件类型表中的一行)。但我认为使用

并不会增加太多麻烦
update domain_events set 
    aggregate_type = 'new class name'
where aggregate_type = 'origin class name'

我不确定我是否理解事件组,你能补充更多解释吗?

3.我不确定,域事件可以有多个有界上下文,或者只有一个,所以我应该将事件上下文存储为 好吗?

有时事件用于集成多个上下文。但是每个事件仅在一个上下文中引发。例如,在 ordering 上下文中引发了 ManualPaymentMadeEvent,在 shipping 上下文中的事件监听器也消费它,将其视为开始发货的触发器。

我更喜欢在每个上下文中使用每个数据库用户(oracle 术语)。 shipping.domain_events 用于运输上下文,ordering.domain_events 用于订购上下文。

这是axon-framework 中的架构,可能会有所帮助

create table DomainEventEntry (
    aggregateIdentifier varchar2(255) not null,
    sequenceNumber number(19,0) not null,
    type varchar2(255) not null,  --aggregate class name
    eventIdentifier varchar2(255) not null,
    metaData blob,   
    payload blob not null, -- details
    payloadRevision varchar2(255),
    payloadType varchar2(255) not null, --event class name
    timeStamp varchar2(255) not null
);

alter table DomainEventEntry
    add constraint PK_DomainEventEntry primary key (aggregateIdentifier, sequenceNumber, type);

【讨论】:

  • 谢谢!我将做一个简化的、受轴突启发的设计。 :-)
  • 哦,顺便说一句。你能推荐任何关于上下文映射的书籍或文章吗? (很难找到关于它的理论文本,但人们通常会提到它,或者至少通过 ddd 提及它。)
  • Domain Driven DesignImplementing Domain Driven Design 都有关于该主题的单独章节。
  • @Hippoom Axon 框架是否仅使用一个表(在您的示例中为DomainEventEntry)来存储系统中所有聚合类型的所有事件?
  • @Songo 默认情况下是的。但是,您也可以从 2.2 版起通过自定义 jpa 实体为每个聚合根使用一个表,issue related
猜你喜欢
  • 2023-03-11
  • 2018-06-24
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-03
  • 1970-01-01
  • 2021-10-01
相关资源
最近更新 更多