事件溯源是什么
事件溯源是以时间顺序记录所发生的领域事件,之后可通过所记录的领域事件得到相应对象当前状态的一种设计理念。这种设计理念从根本上颠覆了以更新方式维护对象状态的传统方式,其优点是保存了聚合(如果还没听说过这个概念,可以先了解下DDD)的操作历史,从而为审计和数据分析提供支持;对于事件只进行插入,也就无需锁和事务,因此性能更好。缺点是数据量会更大;需要重放所有相关事件来得到当前状态;有违大多数开发人员的习惯思维方式。
为什么用事件溯源
在为新类型单据开发支付功能的过程中发现了原支付功能中诸多不合理设计和缺陷,比如表结构(不参与查询的属性定义为表中的列,也就是可以保存为json的数据以结构化方式保存),代码不能应对并发。
原支付功能由payment表负责保存单据的支付状态,每次支付操作的请求数据和回调数据都保存在与payment表结构完全一样的payment_history表中,两个表的唯一的区别是payment_history表的单据编号字段保存的是单据编号 + 支付次数,像这样:0001-1,0001-2。当执行任何与支付有关的操作(支付,拒绝,退款)或接收到支付接口的回调后须同时更新payment和paymeny_history两个表。
支付功能对于任何系统的重要性都不言而喻,因此当初的设计者才会将有关支付的所有操作都记录在paymeny_history这个相当于支付日志的支付历史表中。事件溯源就是为类似这种需要完整保存历史轨迹的需求而量身打造的,但其实这并不是事件溯源的目的,而只是该设计理念所附带的好处。这就是为什么选择以事件溯源来重构支付功能的唯一原因。
如何以事件溯源进行重构
事件溯源的核心是事件,没有事件何以溯源。所以,首先要做的就是从支付流程中识别并提取出所有领域事件。根据本系统支付业务的特点,提取出如下事件:支付数据验证通过,支付数据验证未通过,支付成功,支付失败,退款,拒绝支付。事件对象中属性的定义取决于系统的特点,并没有通用的标准,不过至少要包含事件名和时间两个核心属性。以下是本系统支付领域事件的定义。
public static class StartPay extends Event {
public StartPay(Long billId) {
super(billId, StartPay.class, "开始支付");
}
}
public static class Verified extends Event {
public Verified(Long billId, String data) {
super(billId, Verified.class, data);
}
}
public