【发布时间】:2017-02-12 17:24:22
【问题描述】:
我正在开发一个在客户系统上使用数据库(PostgreSQL、MySQL、Oracle 或 MSSQL)的应用程序。
因此我需要对每个新版本执行数据库更新。
我目前处于概念阶段,没有任何东西在生产中运行。
所有 DDL 语句都在 脚本文件中。
结构如下:
tables\employees.sql
customers.sql
orders.sql
这些脚本也在版本控制中,可用于从stretch构建数据库。
当然,这些表格在未来的某个时候会有变化。
例如表 employees 是这样创建的:
CREATE TABLE if not exists employees
(
EmployeeId serial,
FirstName text,
PRIMARY KEY (EmployeeId)
);
在未来的版本中,该表会得到扩展:
ALTER TABLE employees ADD COLUMN address varchar(30);
在我的研究中,我发现了这个例子:https://stackoverflow.com/posts/115422/revisions。 版本号用于执行特定更改。
我喜欢这个概念,我的想法是实现类似的东西。 但我考虑为每个表引入一个版本,而不是系统版本号。
在创建 employee 表时,它会获得版本号 1。随着该表上的每次更改,版本号都会增加 1。在添加 address 列(更改上面的语句)表版本将是 2。
每个表的更改都会发生在这样的嵌套事务中:
BEGIN TRANSACTION;
UPDATE employees SET Version = 2;
ALTER TABLE employees
ALTER TABLE employees ADD COLUMN address varchar(30);
END TRANSACTION;
如果表版本低于当前表版本,事务将回滚。 该逻辑的实现尚未完成。
好处是表上的所有更改都在表的脚本文件本身内,并且初始语句始终是最新的。
例如,当第一次创建 employee 表时,它看起来像这样:
employees.sql
CREATE TABLE if not exists employees
(
EmployeeId serial,
FirstName text,
Version int default 1 not null,
PRIMARY KEY (EmployeeId)
);
经过一些更改后,它看起来像这样:
employees.sql
CREATE TABLE if not exists employees
(
EmployeeId serial,
FirstName varchar(100),
address varchar(80),
Version int default 3 not null, -- notice the 3
PRIMARY KEY (EmployeeId)
);
-- First Change
BEGIN TRANSACTION;
UPDATE employees SET Version = 2;
ALTER TABLE employees
ALTER TABLE employees ADD COLUMN address varchar(30);
END TRANSACTION;
-- Second Change
BEGIN TRANSACTION;
UPDATE employees SET Version = 3;
ALTER TABLE employees
ALTER COLUMN address TYPE varchar(80),
ALTER COLUMN FirstName TYPE varchar(100);
END TRANSACTION;
这个概念可以接受还是我在这里重新发明轮子?
【问题讨论】:
-
在 MySQL 中,任何 DDL 命令都会导致隐式提交,因此 DDL 更改无法回滚。不知道其他db是什么情况
-
你在正确的轨道上,但你错过了一些东西。 (一方面,更改可能以错误的顺序应用。)像Ruby on Rails 这样的Web 框架通过迁移 管理这些事情。研究他们如何做到这一点可以为您节省大量时间。
标签: mysql sql sql-server oracle postgresql