2016-10-04 2 views
1

Ich entwickle eine Anwendung, die eine Datenbank (PostgreSQL, MySQL, Oracle oder MSSQL) auf dem Kundensystem verwendet.Sql-Änderungen an Kundendatenbanken implementieren (geänderte Tabellen, Funktionen, ...)

Daher muss ich Datenbankaktualisierungen mit jeder neuen Version durchführen.

Ich bin gerade in der Konzeptphase und habe nichts in Produktion.

Alle DDL-Anweisungen sind in Skriptdateien.

Die Struktur sieht wie folgt aus:

tables\employees.sql 
     customers.sql 
     orders.sql 

Diese Skripte sind auch in Versionskontrolle und verwendet werden können, um die Datenbank von Strecke zu bauen.

Natürlich wird es irgendwann in der Zukunft Änderungen an diesen Tabellen geben.

Zum Beispiel Tabelle Mitarbeiter wie folgt erstellt werden:

CREATE TABLE if not exists employees 
(
    EmployeeId  serial, 
    FirstName  text, 

    PRIMARY KEY (EmployeeId) 
); 

Und in einer zukünftigen Version die Tabelle erweitert wird:

ALTER TABLE employees ADD COLUMN address varchar(30); 

Auf meinen Recherchen fand ich dieses Beispiel: https://stackoverflow.com/posts/115422/revisions. Eine Versionsnummer wird verwendet, um bestimmte Änderungen durchzuführen.

Ich mag dieses Konzept und meine Idee ist, etwas ähnliches zu implementieren. Aber statt einer Systemversionsnummer habe ich darüber nachgedacht, für jede Tabelle eine Version einzuführen.

Wenn die Mitarbeiter zu schaffen Tabelle es die Versionsnummer 1. Bei jeder Änderung von 1 auf dieser Tabelle Nach dem Hinzufügen der Adresse der Versionsnummer Spalte (alte Aussage oben) von der Tabelle erhöht wird Version 2 sein würde, . gerollt würde die Transaktion zurück

BEGIN TRANSACTION; 

UPDATE employees SET Version = 2; 

ALTER TABLE employees 
    ALTER TABLE employees ADD COLUMN address varchar(30); 

END TRANSACTION; 

Wenn die Tabelle Version niedriger ist als die aktuelle Tabelle Version:

Jede Tabelle ändern

in einer verschachtelten Transaktion wie dies geschehen würde. Die Implementierung dieser Logik ist noch nicht abgeschlossen.

Der Vorteil wäre, dass alle Änderungen an einer Tabelle innerhalb der Skriptdatei der Tabelle selbst sind und die ursprüngliche Anweisung immer aktuell ist.

Zum Beispiel, wenn zuerst die Mitarbeiter Tabelle erstellt es würde wie folgt aussehen:

Mitarbeiter.sql

CREATE TABLE if not exists employees 
(
    EmployeeId  serial, 
    FirstName  text, 

    Version   int  default 1 not null, 

    PRIMARY KEY (EmployeeId) 
); 

Nach einigen Veränderungen, die sie wie folgt aussieht:

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; 

Ist das Konzept akzeptabel oder bin ich das Rad neu zu erfinden hier?

+1

In MySQL jeder DDL-Befehl bewirkt, dass ein implizites Commit DDL-Änderungen können daher nicht rückgängig gemacht werden. Ich weiß nicht, wie es bei anderen dbs aussieht. – Shadow

+1

Sie haben recht, https://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis – Tommy

+0

Sie sind auf dem richtigen Weg, aber Sie Es fehlen einige Dinge. (Zum einen die Möglichkeit, dass Änderungen in der falschen Reihenfolge angewendet werden.) Web-Frameworks wie Ruby auf Rails verwalten diese Art von Dingen durch * Migrationen *. Forschung darüber, wie sie das tun, würde Ihnen viel Zeit sparen. –

Antwort

2

Ich denke, die Versionsnummer pro Tabelle ist Overkill. Außerdem erschweren Sie die Verwaltung der Datenbank und der Anwendung. Ich empfehle Ihnen, eine neue Tabelle für DB_VersionNumber hinzuzufügen und für jede Aktualisierung eine Zeile in dieser Tabelle hinzuzufügen. Was ich getan habe, ist dies: 1) Erstellen Sie eine Tabelle in DB für Datenbankversionen (Schritte) 2) Erstellen Sie einen SP, der diese Tabelle überprüft und einen DB-Upgrade-Schritt ausführt, wenn es nicht in der Tabelle vorhanden ist, andernfalls den Schritt wird übersprungen. 3) Fügen Sie für jede DB-Änderung einen Schritt in der Upgrade-Skriptdatei hinzu (die Sie bereits erstellt und zur Quellcodeverwaltung hinzugefügt haben).

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 

Dann Ihre Upgrades gelten durch die SP-Aufruf (der Schlüssel ist, dass Sie eine eindeutige Schritt Nummer, die jedes Upgrade-Skript zuweisen haben:

---------------- 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 
' 
Verwandte Themen