Myślałem o tym już od jakiegoś czasu i mogę wymyślić tylko dwa sposoby na zrobienie tego. Oba mogą pracować w pełni przezroczysto, gdy zostaną utworzone w abstrakcyjnej warstwie danych/modelu.
Nawiasem mówiąc, istnieje implementacja "wersjonowalnych" danych tabeli w doktrynie mapowania ORM. Zobacz ten example in their docs. Może to pasuje do twoich potrzeb, ale nie pasuje do moich. Wydaje się, że usuwa wszystkie dane historii po usunięciu oryginalnego rekordu, co sprawia, że naprawdę nie jest to bezpieczne.
Wariant A: mieć kopię każdej tabeli do przechowywania danych rewizji
Powiedzmy, że masz prostą tabelę kontaktowy:
CREATE TABLE contact (
id INT NOT NULL auto_increment,
name VARCHAR(255),
firstname VARCHAR(255),
lastname VARCHAR(255),
PRIMARY KEY (id)
)
można utworzyć kopię tej tabeli i dodać rewizji dane:
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)
)
śledzić INSERT
i UPDATE
użyciu AFTER
wyzwalaczy. Przy każdej nowej wersji danych w oryginale, wstaw kopię nowych danych do tabeli zmian i odpowiednio ustaw modyfikację type
.
Aby zalogować się do wersji DELETE
pod kątem bezpieczeństwa, należy również wstawić nowy wiersz do tabeli historii! W tym celu należy użyć wyzwalacza BEFORE DELETE
i zapisać najnowsze wartości, zanim zostaną usunięte. W przeciwnym razie będziesz musiał usunąć każde ograniczenie NOT NULL
w tabeli historii.
kilka ważnych wskazówek dotyczących tego wdrożenia
- dla tabeli historii należy usunąć każdy
UNIQUE KEY
(tu: PRIMARY KEY
) z tabeli rewizyjnej bo masz ten sam klucz kilka razy dla każdej rewizji danych .
- Po utworzeniu schematu i danych w oryginalnej tabeli za pomocą aktualizacji (na przykład aktualizacji oprogramowania) należy upewnić się, że te same dane lub poprawki schematu zostaną zastosowane do tabeli historii i jej danych. W przeciwnym razie wystąpią problemy, gdy powrócisz do starszej wersji zestawu rekordów.
- W rzeczywistej implementacji chcesz wiedzieć, który użytkownik zmodyfikował dane. Aby było to bezpieczne pod względem integralnym, rekord użytkownika nie powinien nigdy zostać usunięty z tabeli użytkowników. Powinieneś po prostu ustawić konto wyłączone z flagą.
- Zwykle działanie pojedynczego użytkownika obejmuje więcej niż jedną tabelę. W rzeczywistej implementacji trzeba również śledzić, które zmiany w wielu tabelach należą do transakcji jednego użytkownika, a także w jakiej kolejności. W prawdziwym przypadku należy odwrócić wszystkie zmiany pojedynczej transakcji, w odwrotnej kolejności. Wymagałoby to dodatkowej tabeli poprawek, która śledzi użytkowników i transakcje i zawiera luźną relację do wszystkich poszczególnych wersji w tabelach historii.
Korzyści:
- całkowicie w bazie danych, niezależnie od kodu aplikacji. (cóż, nie w przypadku, gdy śledzenie transakcji użytkownika jest ważne, wymagałoby to logiki wykraczającej poza zakres pojedynczego zapytania):
- wszystkie dane są w oryginalnym formacie, bez konwersji typu niejawnego.
- dobra wydajność wyszukiwania w wersjach
- łatwe wycofywanie. Po prostu wykonaj prostą instrukcję
INSERT .. ON DUPLICATE KEY UPDATE ..
w oryginalnej tabeli, używając danych z wersji, którą chcesz przywrócić.
wydarzenia:
- Trudno realizować ręcznie.
- twardy (ale nie niemożliwe) do automatyzacji, jeśli chodzi o migracje baz danych/aktualizacji aplikacji.
Jak już wspomniano powyżej, doctrines versionable
robi coś podobnego.
Wariant B: mają Centralna Tabela Zmian
przedmowę: złe praktyki, pokazany na ilustracji tylko pomocniczo.
Takie podejście ma mocno polegać na logice aplikacji, które powinny być ukryte w warstwie danych/model.
Masz Centralna Tabela historii, która śledzi na
- zrobił
- gdy
- modyfikować, wstawić lub usunąć
- jakie dane
- , w którym pole które
- stół
Podobnie jak w przypadku innych metod, możesz również chcieć śledzić, które indywidualne zmiany danych należą do czynności/transakcji jednego użytkownika i w jakiej kolejności.
Korzyści:
- Nie trzeba zachować w synchronizacji z oryginalnym stole podczas dodawania pól do tabeli lub tworzenie nowej tabeli. skaluje się w sposób przezroczysty.
wydarzenia:
- złych praktyk za pomocą prostego wartość = klucz przechowywać w bazie
- złe wyniki wyszukiwania, z powodu ukrytych konwersji typu
- może spowolnienie ogólną wydajność aplikacji/bazy danych, gdy centralna tabela historia staje się wąskim gardłem powodu blokad zapisu (dotyczy to tylko dla konkretnych silników z zamkami stołowych, czyli MyISAM)
- Jest to znacznie trudniejsze do wdrożenia cofanie
- możliwych błędów konwersji danych/straty precyzji ze względu na niejawna konwersja typu
- nie śledzić zmiany, gdy bezpośredni dostęp do bazy danych gdzieś w kodzie zamiast przy użyciu modelu/warstwy danych i zapomnij, że w tym przypadku musisz ręcznie zapisać w dzienniku wersji. Może być dużym problemem podczas pracy w zespole z innymi programistami.
Wniosek:
- Wariant B może być bardzo przydatny dla małych aplikacjach jak prostego "drop in", gdy jej tylko do rejestrowania zmian.
- Jeśli chcesz cofnąć się w czasie i być w stanie łatwo porównać różnice między historycznym revison rewizji i/lub powrócić do starych danych, a następnie Wariant A jest trudne do zrobienia .
Możesz przeczytać artykuł Wikipedii o wolno zmieniających się wymiarach. –
związane: http://stackoverflow.com/questions/762405/database-data-versioning – Kaii
@ ta.speot.is dzięki będę spojrzeć – safarov