event-sourcing - 事件存储是否存储状态?
问题描述
从理论上讲,当使用事件源时,您不存储“状态”而是存储事件。但是我在许多实现中看到,您将状态快照以 JSON 或 BLOB 之类的格式存储在列中。例如:
事件表具有存储整个对象的数据列。对我来说,这就像在某个事件发生的给定时间存储状态。
还有这张照片(取自Streamstone):
它具有具有序列化状态的数据列。所以它也存储状态但在事件中?
那么如何从初始状态重播,如果我可以简单地选择一些事件并访问数据直接获取状态。
Data 中究竟存储了什么,是整个对象的状态还是序列化事件?
假设我有一个人对象(在 C# 中)
public class Person
{
public string Name { get; set }
public int Age { get; set; }
}
当我创建一个人或更改姓名或年龄等属性时,我的事件应该存储什么。
当我创建一个 Person 时,我很可能会发送PersonCreatedEvent
带有初始状态的东西,因此是整个对象。
但是,如果我更改姓名或年龄,它们应该是 2 个单独的事件还是只有 1 个呢?PersonChangedEvent
或PersonChangedAgeEvent
和PersonChangedNameEvent
?
在这种情况下应该在事件中存储什么?
解决方案
Data 中究竟存储了什么,是整个对象的状态还是序列化事件?
这通常是事件的序列化表示。
一种思考方式:事件流类似于补丁文档流。当前状态的计算方法是从一些已知的默认状态开始,然后依次应用每个补丁——也就是“折叠”。可以通过选择流中的某个点并将补丁应用到该点来恢复以前的状态。
与补丁不同,事件的语义往往是特定于域的。所以Checked-In
,Checked-Out
而不是Patched
,Patched
。
我们通常保持事件紧凑 - 您通常不会记录未更改的状态。
在您的领域特定事件语言中,事件中字段的语义可能是“替换”——例如,当记录名称的更改时,我们可能只存储整个新名称。在其他情况下,改为“汇总”可能是有意义的——使用诸如帐户余额之类的东西,您可能会记录贷方和借方,从而得出余额,或者您可能会更新总余额(如仪表)。
在大多数成熟领域(银行、会计)中,领域语言具有用于记录更改的语义,而不是级别。我们将新条目写入分类帐,我们将新条目写入支票簿寄存器,我们在帐户对帐单中读取已完成和待处理的交易。
但是,如果我更改姓名或年龄,它们应该是 2 个单独的事件还是只有 1 个呢?PersonChangedEvent 或 PersonChangedAgeEvent 和 PersonChangedNameEvent?
这取决于。
交易产生多个事件并没有错。
拥有一个可以以多种方式重用的单一事件模式并没有错。
拥有不止一种改变相同字段的事件并没有错。 NameLegallyChanged
并且SpellingErrorCorrected
可能是业务的一个有趣区别。
激发基于任务的 UI的许多相同问题也适用于事件模式的设计。
在我看来,PersonChangedEvent 仍然会包含所有可以更改的人员属性。即使他们没有改变
在消息传递中(事件设计从消息设计中吸取了很多教训),我们经常设计带有可选字段的模式。因此,事件模式可以非常灵活,而事件的任何单独表示都将是紧凑的(仅限于感兴趣的信息)。
推荐阅读
- python - Python pip install 找不到模块
- java - 在 Mono 上使用 elapsed() 函数?
- c - 如何检查 CLI 定义的 MACRO (-DMACRO=) 是否已定义
- swiftui - 更改选项卡式视图栏颜色 SwiftUI
- java - 如何在骆驼项目中处理蓝图路线中的异常
- php - 在 000webhost.com 上安装 Laravel 项目时出错
- python - 如何减少过期请求?
- jsp - JSP - 未解析的自定义标签
- sql - 如何在 Ruby on Rails 5 中检索随机 GET 请求?
- sql - 在 SQL 中排除大量字符串 (500) 的最简单方法?