3

我们目前正在用 Java 开发基于用户的 Web 应用程序。

用户可以拥有许多属性,例如名字、姓氏、地区(例如亚洲、欧洲、美国、英国)、国家、部门、分支、产品等。

该用户具有上述所有字段的正常 CRUD 屏幕。

用户的添加/编辑屏幕还将有一个称为生效日期的日期字段。此添加/编辑用户与常规 CRUD 中的普通添加/编辑不同的方式是,对用户所做的更新将在生效日期之前反映。

假设今天是 4 月 6 日,我添加了一个新用户,区域为亚洲,生效日期为 4 月 10 日。现在我去更改同一个用户并将他的区域从亚洲更改为美国,但生效日期为 5 月 15 日。

因此,直到 5 月 15 日,系统应仅将他的地区显示为亚洲,并且在 5 月 15 日,他的地区应自动更改为美国。

您可以将其视为 4 月在亚洲工作的用户,但从 5 月 15 日起,他将搬到美国工作,即地区从亚洲更改为美国,5 月 15 日生效。所以在 5 月 15 日之前,他应该只在亚洲显示为用户。

所以我不能把他的区域从亚洲更新到我们数据库中作为一个简单的更新操作。

这也适用于许多其他领域,如部门、分支和产品。

我不能为同一个用户拥有多条记录。

编辑1:

我们还应该能够看到用户历史记录或未来的更新。

就像 4 月 6 日一样,我应该看到用户区域将从 5 月 15 日开始更改,他的部门将从 5 月 10 日开始从 A 更改为 B。

我也应该能够删除更新,说我稍后才知道,从亚洲到美国的拟议转移用户可能不会在 15 日生效,所以我应该能够删除该更新。

编辑2:-

鉴于上述情况,我如何在我的原始用户表和用户更改日志表中进行更改?

假设系统中有一个亚洲地区的用户,该用户将在接下来的几周内从亚洲更改为我们。用户将对用户有相同的更新。他将地区从亚洲更改为用户,并选择生效日期作为未来日期。

现在我如何检查区域是否从亚洲更改为我们(可以有像区域这样的名称 mre 字段)。我应该在代码级别执行此操作,还是可以使用触发器等在数据库级别执行此操作?

请帮助我为此设计系统和数据库。

4

7 回答 7

1

您可以创建一个User_Region包含User_ID,Region_ID和的映射表Change_DateChange_Date将在用户的区域切换发生时给出。当更改日期为空时,这可能意味着用户当前位于该区域。

然后,您可以获得一个地区列表User_ID以及日期,可以根据您的方便显示。

CREATE TABLE User_Regions{
   User_ID INT,
   Region_ID INT,
   Change_Date DATE,
   FOREIGN KEY User_ID REFERENCES User(ID),
   FOREIGN KEY Region_ID REFERENCES Region(ID)
};
于 2012-04-06T12:26:33.153 回答
1

历史表可以解决问题。这意味着,拥有尽可能多的带有日期列的历史记录,并且只将最接近当前日期的记录视为当前记录。否则,您必须将更新历史记录保存在单独的表中,并有一个批量更新过程来更新更改。我建议尝试通过获取用户实体的规范化结构来克服无法为同一用户拥有多个记录的障碍:用户表将具有关键列(例如 id)和一个包含历史更新的连接表以及其余部分列。

于 2012-04-06T12:26:42.300 回答
1

我建议您可以实现这个系统,维护一个CHANGELOG 表和一个调度程序,该调度程序将在每天的特定时间运行。

CHANGELOG 表 属性:

  • 目标表
  • 目标主键
  • 目标列
  • 目标价值
  • 生效日期

现在,每当对必填字段进行更新时,在更改日志表中插入相应的条目。

例子,

  • 目标表:用户
  • targetPrimaryKey : 3(用户记录的主行ID)
  • 目标列:区域
  • 目标值:美国
  • 生效日期:2012 年 5 月 15 日

现在,调度程序将每天运行(例如上午 12:00),并将检查当天从 CHANGELOG 表中进行的计划更改,并在相应的目标表中进行这些更改。

注意:这种方法有两个优点:

  1. 您不必为同一记录维护两个条目。

  2. 您也可以定位多个字段(区域、部门、分支)和多个表。

于 2012-04-06T12:30:48.210 回答
0

你有两种可能:

  1. 你有一个不同的表,看起来像你的用户表,并且有一个额外的列“validFrom”,然后每天早上都有一个 cron (quartz) 作业更新。
  2. 您将该列与有效的用户表一起添加到您的常规用户表中,并更改您的所有查询以反映这一点。

正如您已经说过的,您不能有多个记录,所以 2. 将是一个糟糕的解决方案。坚持1。

于 2012-04-06T12:26:53.810 回答
0

“纯”数据模型将在密钥中包含一个日期,并且有多个版本,但是在更改未来事件方面存在一些问题。

我想我会尝试将未来的更改建模为“操作”列表,并且将来更改字段实际上是安排将在该日期修改字段的操作。

应用程序会在操作到期时定期应用操作。

在 GUI 中,显示待处理操作的列表很简单,并且很容易取消或修改未来的操作。

您可以设置规则来限制或发出冲突操作的警告,但如果列表清晰可见,那就不是问题了。

于 2012-04-06T12:29:02.407 回答
0

在我看来,您应该使用 Event 语句。以下是 2 个事件:

CREATE EVENT myevent
    ON SCHEDULE AT DATE_CHANGING
    DO
      UPDATE myschema.mytable SET mycol = mycol + 1;

CREATE EVENT myevent
    CREATE EVENT myevent
    ON SCHEDULE AT DATE_BACKUP
    DO
      UPDATE myschema.mytable SET mycol = mycol - 1;
于 2012-04-06T12:29:24.167 回答
0

我可以想到两种方法:

将所有版本保留在主表中

| user_name (PK) | effective_date_from (PK) | ...remaining columns

在这种方法中,每个用户都由 table 中的几行表示,User但只有一行是current。为了找到当前数据,您需要添加一些额外的查询:

SELECT *
FROM User
WHERE user_name = ?
  AND effective_date >= NOW()
ORDER BY effective_date DESC
LIMIT 1

因此,我们正在获取所有具有给定的用户user_name(此类用户的多个版本具有不同的effective_date,因此effective_date也必须是主键的一部分)。我们将结果限制为最新版本(但effective_date将来不会)。

这种方法有几个缺点:

  • 外键怎么办?逻辑上系统中只有一个用户
  • 性能差,查询复杂
  • 如何处理过时的版本?

待定版本表

保持原始(主)User表模式不做任何更改,并有第二个表名为Pending_user_changes. 后者也将具有相同的架构 +effective_date列。如果更改的粒度是一天,请编写一个作业(在数据库或应用程序中),查找应从今天开始生效的任何未决更改并替换主表。

我发现这个解决方案更干净:主表中的主键/外键永远不会改变,main表也不会被旧的和重复的数据弄乱。

于 2012-04-06T12:30:06.433 回答