我正在开发一个在客户系统上使用数据库(PostgreSQL,MySQL,Oracle或MSSQL)的应用程序。
因此,我需要为每个新版本执行数据库更新。
我目前处于概念阶段,并没有在生产中运行。
所有DDL语句都在脚本文件中。
结构如下:
tables\employees.sql
customers.sql
orders.sql
这些脚本也在版本控制中,可用于从拉伸构建数据库。
当然,将来某些时候会对这些表格进行更改。
例如,表员工的创建方式如下:
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。 版本号用于执行特定更改。
我喜欢这个概念,我的想法是实现类似的东西。 但我没有考虑系统版本号,而是考虑为每个表引入一个版本。
创建员工表时,会获得版本号1.随着该表的每次更改,版本号增加1.添加地址列后(更改上面的声明)表格版本为2。
每个表更改都会发生在嵌套事务中,如下所示:
BEGIN TRANSACTION;
UPDATE employees SET Version = 2;
ALTER TABLE employees
ALTER TABLE employees ADD COLUMN address varchar(30);
END TRANSACTION;
如果表版本低于当前表格版本,则将回滚该事务。 该逻辑的实现尚未完成。
好处是表的所有更改都在表的脚本文件本身内,并且初始语句始终是最新的。
例如,首次创建员工表时,它将如下所示:
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;
这个概念是否可以接受,还是我在这里重新发明轮子?
答案 0 :(得分:2)
我认为设置每个表的版本号是过度的。此外,它使DB和应用程序的管理变得复杂。我建议您为DB_VersionNumber添加一个新表,并在此表中为每次升级添加一行。我一直在做的是: 1)在DB中为数据库版本创建一个表(步骤) 2)如果表中不存在,则创建一个检查此表并运行数据库升级步骤的SP,否则跳过该步骤。 3)对于每个数据库更改,在升级脚本文件中添加一个步骤(您已创建并添加到源代码管理中)。
Here is the table and the SP:
IF OBJECT_ID (N'DB_Version', N'U') IS NULL
Begin
CREATE TABLE [DB_Version](
[VersionNumber] [decimal](18, 2) NOT NULL,
[CommitTimestamp] [smalldatetime] NOT NULL
) ON [PRIMARY]
ALTER TABLE DB_Version
ADD CONSTRAINT UQ_VersionNumber UNIQUE (VersionNumber);
End
IF OBJECT_ID ( 'NewDBStep', 'P' ) IS NULL
begin
Exec ('
-- ============================================
-- Description: Applies a new DB upgrade step to the current DB
-- =============================================
CREATE PROCEDURE NewDBStep
@dbVersion [decimal](18, 2),
@script varchar (max)
AS
BEGIN
If not exists (select 1 from DB_Version Where VersionNumber = @dbVersion)
Begin
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRY
Begin tran
Exec (@script)
Insert into DB_Version (VersionNumber, CommitTimestamp) Values (@dbVersion, CURRENT_TIMESTAMP);
Commit tran
Print ''Applied upgrade step '' + Cast ( @dbVersion as nvarchar(20))
END TRY
BEGIN CATCH
Rollback tran
Print ''Failed to apply step '' + Cast ( @dbVersion as nvarchar(20))
Select ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
END CATCH
End
END ') ;
End
然后,通过调用SP来应用您的升级(关键是您必须为每个升级脚本分配一个唯一的步骤编号:
---------------- Add the new steps here
-- Step: 0.01
-- Adding the MyTableName table if it does not exist.
Exec NewDBStep 0.01, '
IF OBJECT_ID (N''MyTableName'', N''U'') IS NULL
Begin
CREATE TABLE [MyTableName](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserType] [nvarchar](20) NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
End
'
Exec NewDBStep 1.00, '
-- Some other DDL script
'