如何版本化关系数据?

时间:2013-09-19 20:09:25

标签: mysql

版本控制很简单,例如page的条目有name。我会有一个表page_version,无论是使用触发器还是应用程序逻辑,每次更新page时都会存储该行的每个先前值。

CREATE TABLE `page` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `page` (`id`, `name`)
VALUES
    (1,'Foo');

CREATE TABLE `page_version` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `page_id` int(10) unsigned NOT NULL,
  `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `entry_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `page_id` (`page_id`),
  CONSTRAINT `page_version_ibfk_1` FOREIGN KEY (`page_id`) REFERENCES `page` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `page_version` (`id`, `page_id`, `name`, `entry_timestamp`)
VALUES
    (1,1,'foo','2013-09-19 20:27:06');

在这个例子中,我知道page.name已从“foo”更改为“Foo”。如果它再次被更改(例如,更改为“Bar”),则“Foo”值将添加到page_version,原始行page.name更新为“Bar”。

但是,如何跟踪可能与条目具有一对多关系的相关值的版本?例如如果通过添加categorycategory_page表来补充后一个模式。

CREATE TABLE `category` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `category` (`id`, `name`)
VALUES
    (1,'One'),
    (2,'Two');

CREATE TABLE `page_category` (
  `page_id` int(10) unsigned NOT NULL,
  `category_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`page_id`,`category_id`),
  KEY `category_id` (`category_id`),
  CONSTRAINT `page_category_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) ON DELETE CASCADE,
  CONSTRAINT `page_category_ibfk_1` FOREIGN KEY (`page_id`) REFERENCES `page` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

如果用户在页面中添加了新类别(“2”),如何捕获更改(在foo更改为Foo时的相同更改)?

2 个答案:

答案 0 :(得分:0)

如果要在同一位置跟踪版本(比如相同的entry_timestamp字段),可以使用page_category表上的触发器实现该版本。 查看更多here,该页面底部有一个示例。

答案 1 :(得分:0)

您使用术语“版本”但是,正如jeremycole所评论的那样,您不清楚原因是否需要它。

如果只是提供数据随时间变化的历史记录,那么数据库中每个表的附加表就足够了;看来这就是您在page_version表格中已有的内容。

这些历史记录表将允许您在某个时间点从数据库中检索“对象”的状态,这就是我使用术语“历史记录”的原因。将其称为版本意味着将数字或其他标识符应用于定义“对象”的数据集合。您似乎没有在表结构中使用它。

从一个时间点重建关系数据将涉及编写加入适当表的常规查询,但在您感兴趣的时间点或之前添加匹配数据行。虽然这可以完成后,当连接中的表数增加时,它变得难以处理。

另一种方法是在应用程序中创建对象的一个​​版本并将其存储在数据库中。例如,使用XML或JSON对对象进行编码,并将整个事物(作为字符串)与版本号和日期戳一起放在表中。

这使得在给定版本号的情况下检索整个对象变得容易,尽管它需要应用程序在再次将数据写入数据库之前从XML / JSON数据构造内存中对象(如果您想要的话)恢复到以前的版本)。这应该不会太难,因为您已经在读取/写入关系表的对象,您只需要添加对象流代码。

在不了解存储历史/版本的原因的情况下,很难推荐一种方法而不是另一种方法。我使用由触发器管理的简单历史表来记录系统中数据的更改,但是我们没有要求“回滚”到以前的版本。我们使用历史记录进行奇怪的场合,我们需要撤消单个编辑,并通过记录进行更改的人的用户名作为“责备”路径:)

我建议您阅读Richard Snodgrass撰写的Developing Time-Oriented Database Applications in SQL(PDF链接位于“图书”部分的第一段)。这不是一本简短的书,但它对我帮助很大。