Architecture 如何在数据库中持久化事件日志数据?

Architecture 如何在数据库中持久化事件日志数据?,architecture,domain-driven-design,Architecture,Domain Driven Design,在我的应用程序中,我强烈要求记录实体的每个事件,并考虑使用模式,即所有域更改都有显式类,对域对象的任何更改只能使用这些事件类。然后,您可以根据需要回滚并重新应用这些更改,就像在源代码管理系统中一样 这将为我解决许多问题,但我不知道如何将事件对象持久化到db。我可能有数百种事件类型,因此我的选项有限: 为每种事件类型构建一个表(数百个表?对实体的引用如何?) 为所有事件构建一个巨大的表(有数千列?) 以某种方式将事件的二进制表示形式存储在db(??) 将其存储在某个单独的文件中(?) 你知道如

在我的应用程序中,我强烈要求记录实体的每个事件,并考虑使用模式,即所有域更改都有显式类,对域对象的任何更改只能使用这些事件类。然后,您可以根据需要回滚并重新应用这些更改,就像在源代码管理系统中一样

这将为我解决许多问题,但我不知道如何将事件对象持久化到db。我可能有数百种事件类型,因此我的选项有限:

  • 为每种事件类型构建一个表(数百个表?对实体的引用如何?)
  • 为所有事件构建一个巨大的表(有数千列?)
  • 以某种方式将事件的二进制表示形式存储在db(??)
  • 将其存储在某个单独的文件中(?)

你知道如何做到这一点吗?

有一个很好的模拟现实生活的会计系统。每一个专业会计系统基本上都是基于交易日记账,这些日记账为财务状况的每一次变化提供了背景——相当于实体的状态变化

我经常使用这种模式,它通常是一组(不是太多)表,其中至少有一个主键、一个时间戳和一个用户名

如果您想分享一下您的实体模型,我们可以讨论一些具体的案例。但通常情况下,表的结构会从与记录的真实事件相关的用例中消失

一些好处-

  • his对于您的设计来说是一个很好的用户关系钩子,因为它是数据库中为数不多的、不言自明的表之一。(“是的,人们就是这样做的,他们这样做的时候需要记录下来。”)

  • 它为处理来自多个可能无法实时集成的源的事务提供了一些现实生活中的灵活性,但您需要重建年表。(例如,从A点到B点和C点到D点的运输)


  • 这里的基本问题是,您有一个完全不相关的模型,您正试图将其与关系数据库相匹配。这样做不会很好。因此,先从细节开始,思考一下你的两个基本方向选择:

  • 您可以尝试构建一个更加关系化的模型。如果您走这条路,可能最好从数据库本身的角度来考虑它,并且现在或多或少地忽略编程方面:什么模式最能表达您的业务领域

  • 您可以坚持使用OO模型,并使用任何存储

  • 对于第二个选项,您有多种可用的存储选项,您可以自由选择其中的一种

    RDBMS是一种选择,尽管您的模式将是相当非关系的,并且您将无法利用RDBMS提供的一些强大的关系工具。我不会为此感到难过:如果你考虑了这两种模式,并决定采用OO,那么你已经有意识地做出了选择。最有可能的是,您的模式最终看起来像一个事件表,每个事件都有一个类型名,每个事件都有一个键值形式的属性表

    一个对象数据库可以让你把你的东西保存在和你在内部使用的形式差不多的地方,这可能很方便。但是,请注意,如果您有性能问题,则此选项可能是最难分析和加速的

    平面文件是一个有趣的选择:只需将对象序列化为某种合理的形式并写出它们。这通常是最快的方式,因为它提供了(特别是如果您对文件进行gzip处理的话)最快的格式之一,可以对数据进行完整扫描。如果您需要经常执行特定的查询,只选择分布在整个集合中的一小部分数据,那么使用某种可以使用索引的DBMS可能会有所帮助,但是如果您处于一个大部分时间都在扫描的位置,DBMS只会减慢您的速度。请注意,您可以(也可能会)通过将内容放在不同的文件中,将其划分为一个维度,甚至两个维度。如果您有十几个基本业务领域,在这些领域中您记录了您经常单独查询的事件,那么您可以为每个领域使用一个单独的文件,并且您还可以每月或每年滚动这些文件

    在这类事情上,我经常会遇到很多挫折,但Unix的管道、文本处理工具和脚本语言的成功证明了这一点,这类事情确实有效。十五年后,web服务器日志的标准仍然是文本格式,看看它产生的所有分析工具

    不管怎样,一旦序列化,您就有了很多其他存储选项。您可以将序列化的块存储在Berkeley DB中,也可以将列存储在RDBMS中

    至于序列化本身,这里也有各种选择,您应该考虑。大多数语言都有某种标准的二进制序列化格式,可以序列化所有内容并返回完整的对象。这些通常很复杂,并且存在版本控制问题,等等。我通常发现使用简单的自定义格式要容易得多。我可以像一个ASCII行一样简单,带有名称和键值列表:

    InvoiceCreate invoice_number=12345 date=2009-05-21 salesperson="Jill Gaines" ...
    
    这有很多好处:

    • 它是人类可读的,因此易于调试
    • 这样的文件可以通过grep、sed、awk等进行处理,以便进行特别查询
    • 它是人工编写的,有利于调试、测试和修复损坏的数据
    • 这很容易解析
    • 它没有链接到任何特定的对象结构、格式甚至语言,因此您可以轻松地更改应用程序,而不必担心与序列化数据的兼容性
    • 当您需要更改数据时,数据本身可以很容易地更新(通常使用简单的sed脚本!)