Už o tom nějakou dobu přemýšlím a napadají mě jen dva způsoby, jak to udělat. Oba mohou fungovat plně transparentně, když jsou vytvořeny do abstraktní datové vrstvy / modelu.
Mimochodem, v doktríně mapovače ORM existuje implementace pro "verzovatelná" tabulková data. Podívejte se na tento příklad v jejich dokumentech . Možná to vyhovuje vašim potřebám, ale nevyhovuje mým. Zdá se, že po smazání původního záznamu smaže všechna data historie, takže není skutečně bezpečný pro revize.
Možnost A:mít kopii každé tabulky pro uložení dat revizí
Řekněme, že máte jednoduchou tabulku kontaktů:
CREATE TABLE contact (
id INT NOT NULL auto_increment,
name VARCHAR(255),
firstname VARCHAR(255),
lastname VARCHAR(255),
PRIMARY KEY (id)
)
Vytvořili byste kopii této tabulky a přidali data revize:
CREATE TABLE contact_revisions (
id INT NOT NULL,
name VARCHAR(255),
firstname VARCHAR(255),
lastname VARCHAR(255),
revision_id INT auto_increment,
type ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
change_time DEFAULT current_timestamp,
PRIMARY KEY(revision_id)
)
Sledujte INSERT
a UPDATE
pomocí AFTER
spouštěče. Na každou novou revizi dat v originálu vložte kopii nových dat do tabulky revizí a nastavte úpravu type
správně.
Pro přihlášení DELETE
revizně bezpečné, musíte také vložit nový řádek do tabulky historie! K tomu byste měli použít BEFORE DELETE
spustit a uložit nejnovější hodnoty před jejich odstraněním. Jinak budete muset odstranit všechny NOT NULL
omezení také v tabulce historie.
Některé důležité poznámky týkající se této implementace
- Pro tabulku historie musíte zrušit každý
UNIQUE KEY
(zde:PRIMARY KEY
) z tabulky revizí, protože budete mít stejný klíč několikrát pro každou revizi dat. - Když
ALTER
schéma a data v původní tabulce prostřednictvím aktualizace (např. aktualizace softwaru), musíte zajistit, aby stejná data nebo opravy schématu byly aplikovány i na tabulku historie a její data. Jinak se při návratu ke starší revizi sady záznamů dostanete do problémů. - Ve skutečné implementaci byste chtěli vědět, který uživatel upravil data. Aby bylo toto revizní bezpečné, neměl by být uživatelský záznam nikdy odstraněn z tabulky uživatelů. Měli byste pouze deaktivovat účet pomocí příznaku.
- Jedna uživatelská akce obvykle zahrnuje více než jednu tabulku. V reálné implementaci byste také museli sledovat, které změny ve více tabulkách patří k jedné uživatelské transakci a také v jakém pořadí. Ve skutečném případě použití byste chtěli vrátit všechny změny jedné transakce dohromady v obráceném pořadí. To by vyžadovalo další tabulku revizí, která sleduje uživatele a transakce a udržuje volný vztah ke všem těmto jednotlivým revizím v tabulkách historie.
Výhody:
- zcela v databázi, nezávisle na kódu aplikace. (No, ne, když je důležité sledování uživatelských transakcí. To by vyžadovalo určitou logiku mimo rozsah jediného dotazu)
- všechna data jsou v původním formátu, žádné implicitní konverze typu.
- dobrý výkon při vyhledávání v revizích
- snadné vrácení zpět. Stačí provést jednoduchý
INSERT .. ON DUPLICATE KEY UPDATE ..
příkaz na původní tabulku s použitím dat z revize, kterou chcete vrátit.
Přednosti:
- Těžko se ručně implementuje.
- Těžké (ale ne nemožné) automatizovat, pokud jde o migrace databází / aktualizace aplikací.
Jak již bylo uvedeno výše, doktríny versionable
dělá něco podobného.
Možnost B:mít centrální tabulku protokolu změn
předmluva:špatný postup, zobrazený pouze pro ilustraci alternativy.
Tento přístup silně spoléhá na aplikační logiku, která by měla být skryta v datové vrstvě/modelu.
Máte centrální tabulku historie, která sleduje
- Kdo to udělal
- kdy
- upravit, vložit nebo odstranit
- jaká data
- ve kterém poli
- z které tabulky
Stejně jako v jiném přístupu můžete také chtít sledovat, které jednotlivé změny dat patří k jedné akci / transakci uživatele a v jakém pořadí.
Výhody:
- při přidávání polí do tabulky nebo vytváření nové tabulky není třeba udržovat synchronizaci s původní tabulkou. měří se transparentně.
Přednosti:
- špatný postup při používání jednoduché hodnoty =úložiště klíčů v databázi
- špatný výkon vyhledávání kvůli implicitním typům konverzí
- může zpomalit celkový výkon aplikace/databáze, když se centrální tabulka historie stane úzkým hrdlem kvůli zámkům zápisu (toto platí pouze pro konkrétní stroje se zámky tabulek, např. MyISAM)
- Implementace vrácení zpět je mnohem těžší
- možné chyby převodu dat / ztráta přesnosti v důsledku převodu implicitního typu
- nesleduje změny, když přímo přistupujete k databázi někde ve vašem kódu namísto použití vaší modelové / datové vrstvy a zapomeňte, že v tomto případě musíte do protokolu revizí zapisovat ručně. Může to být velký problém při práci v týmu s jinými programátory.
Závěr:
- Možnost B může být velmi užitečné pro malé aplikace jako jednoduché "vhození", když je to jen pro protokolování změn.
- Pokud se chcete vrátit v čase a mít možnost snadno porovnat rozdíly mezi historickými revizemi 123 na revizi 125 a/nebo se vrátit ke starým datům a poté Možnost A je obtížná cesta.