2016-10-04 2 views
1

Я разрабатываю приложение, использующее базу данных (PostgreSQL, MySQL, Oracle или MSSQL) в системе клиентов.Развернуть Sql Изменения в клиентских базах данных (измененные таблицы, функции, ...)

Поэтому мне нужно обновлять базы данных с каждой новой версией.

В настоящее время я нахожусь в концепции и не имею ничего работающего в производстве.

Все операторы 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; 

Если версия таблицы ниже, чем текущая версия таблицы сделка будет откат. Побуждение этой логики еще предстоит сделать.

Преимущество состоит в том, что все изменения в таблице находятся внутри самого скриптового файла таблицы, и исходный оператор всегда обновляется.

Например, когда первый создающего сотрудника таблицы это будет выглядеть следующим образом:

сотрудников.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; 

Это понятие приемлемо или я изобретать колесо здесь?

+1

В MySQL любая команда DDL приведет к неявной фиксации , поэтому изменения DDL не могут быть откатны. Я не знаю, в чем ситуация для других dbs – Shadow

+1

Вы правы, https://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis – Tommy

+0

Вы на правильном пути, но вы «Некоторые вещи отсутствуют. (Во-первых, возможность того, что изменения могут быть применены в неправильном порядке.) Веб-фреймворки, такие как Ruby Rails управляет этими вещами через * миграции *. Исследование того, как они это делают, сэкономит вам много времени. –

ответ

2

Я думаю, что установка номера версии за столом является излишним. Кроме того, это затрудняет управление БД и приложением. Я предлагаю вам добавить новую таблицу для DB_VersionNumber и добавить одну строку в эту таблицу для каждого обновления. Что я делал, так это: 1) Создайте таблицу в БД для версий базы данных (шаги) 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 
' 

 Смежные вопросы

  • Нет связанных вопросов^_^