欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

如何设计一张事件记录流水表(版本2)

程序员文章站 2022-05-31 16:22:08
...

在设计完 版本1的事件记录表 后,大家就开始马不停蹄写代码去新增事件记录数据。

 

版本1:事件表

流水ID

id

对象ID

obj_id

系统编码

sys_code

网点编码

area_code

操作者工号

operator_id

源状态

source_status

事件编码

event_code

事件描述

event_desc

目标状态

target_status

创建时间

create_time

123456 A111 TEST_SYSTEM XXX 0123777 初始 001 打印 打印完成 2018-09-06 18:33:35
123457 A111 TEST_SYSTEM QQQ 0123666 打印完成 002 核销 核销完成 2018-09-07 12:05:43

改进:   

       在记录事件的源状态StateA时,一开始的做法是获取其他业务数据表中某对象的当前状态,来设置事件记录表的源状态。但在一些业务场景下,对于同一个事件编码event_code,虽然目标状态StateB是一样的,但是源状态StateA会有很多种情况,此时如果通过业务数据表的当前状态来设置源状态的值,会十分繁琐,而且业务代码上需要知道当前状态,不够透明。

       基于上面情况,我们不再从其他业务数据表中获取某对象的当前状态,而是依赖于事件记录表前后的数据,从版本1的表中,可看到,在按照创建时间排序的前提下,ID为123457的源状态(打印完成),就是上一条记录ID为123456的目标状态(目标状态)。所以想要设置某对象的源状态,只要找到该对象在事件记录表中的上一条记录的目标状态即可  

       但这种方案,严重依赖于上一条记录,当有多个节点同时都往这个事件记录表插入数据时,要对这“上一条记录”的数据进行锁定,需要采用分布式锁或者数据库锁的机制

       

再次改进:

       认真想想,由于事件记录表是按照对象做动作时按时间顺序插入的,只要保证时间顺序,其实可以不需要记录源状态,每条数据的目标状态,也相当于它上一条数据的源状态。因此,我们对事件表进行改造,形成版本2:

版本2:事件表

流水ID

id

对象ID

obj_id

系统编码

sys_code

网点编码

area_code

操作者工号

operator_id

事件编码

event_code

事件描述

event_desc

目标状态

target_status

创建时间

create_time

123456 A111 TEST_SYSTEM XXX 0123777 001 打印 打印完成 2018-09-06 18:33:35
123457 A111 TEST_SYSTEM QQQ 0123666 002 核销 核销完成 2018-09-07 12:05:43

由于事件记录表本身的时间顺序的特性,所以版本2的表基本可以满足我们记录对象全生命周期的需求。还是版本1的需求,比如我们想知道对象A111从打印完成状态到核销完成状态所花费的时间,用sql更容易就实现了:

开始时间:

SELECT create_time AS begin_time FROM db_event_report WHERE obj_id = 'A111' AND target_status = '打印完成';

结束时间:

SELECT create_time AS end_time FROM db_event_report WHERE obj_id = 'A111' AND target_status = '核销完成';

然后将上面两条sql查询出来的begin_time和end_time套入以下sql函数,即可算出相隔的分钟数

SELECT TIMESTAMPDIFF(MINUTE, begin_time, end_time);

 

至此,我们的事件记录流水表设计结束。