Dina granskningsdata bör lagras per tabell, snarare än alla på ett ställe. Vad du skulle göra är att skapa en granskningstabell för var och en av de tabeller du vill spåra, och skapa utlösare för att skapa en post i granskningstabellen för alla datamanipuleringsåtgärder på den granskade tabellen.
Det är definitivt tillrådligt att inte tillåta DELETE
operationer på items
och item_options
tabeller – lägg till flaggor som item_active
och item_option_active
så att du kan softdelete dem istället. Detta är normal praxis i situationer där du gör saker som att lagra fakturor som refererar till produkter som beställts tidigare och behöver data för historiska rapporteringsändamål, men inte för daglig användning.
Dina granskningstabeller är inte något du bör använda för att referera till gamla data, din normala datamodell bör helt enkelt stödja att "gömma" gamla data där det är troligt att det fortfarande kommer att användas, och lagra flera versioner av data som kommer att förändras över tiden.
För granskning är det också användbart att lagra användarnamnet för den senaste användaren för att ändra en given post - när den används från en webbapplikation kan du inte använda MySQL:s USER()
funktion för att få användbar information om vem som är inloggad. Att lägga till en kolumn och fylla i den betyder att du kan använda den informationen i dina granskningsutlösare.
Obs! Jag antar att du inte kommer att tillåta att artikel-ID:n ändras under normala förhållanden - det skulle göra ditt revisionssystem mer komplext.
Om du lägger till aktiva flaggor och data som senast ändrats av dina tabeller kommer de att se ut ungefär så här:
Artikeltabell:
mysql> desc items;
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| item_id | int(11) | NO | PRI | NULL | auto_increment |
| item_name | varchar(100) | YES | | NULL | |
| item_description | text | YES | | NULL | |
| item_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
Tabell för objektalternativ:
mysql> desc item_options;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| option_id | int(11) | NO | PRI | NULL | auto_increment |
| item_id | int(11) | YES | MUL | NULL | |
| option_name | varchar(100) | YES | | NULL | |
| option_price | int(11) | YES | | NULL | |
| option_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
Dina granskningstabeller behöver lagra fyra extra uppgifter:
- Revisions-ID – detta ID är endast unikt för historien om denna tabell är det inte ett globalt värde
- Ändring gjord av - databasanvändaren som gjorde ändringen
- Ändra datum/tid
- Åtgärdstyp -
INSERT
ellerUPDATE
(ellerDELETE
om du tillät det)
Dina granskningstabeller bör se ut ungefär så här:
Revisionstabell för objekt:
mysql> desc items_audit;
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| audit_id | int(11) | NO | PRI | NULL | auto_increment |
| item_id | int(11) | YES | | NULL | |
| item_name | varchar(100) | YES | | NULL | |
| item_description | text | YES | | NULL | |
| item_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
| change_by | varchar(50) | YES | | NULL | |
| change_date | datetime | YES | | NULL | |
| action | varchar(10) | YES | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
Revisionstabell för objektalternativ:
mysql> desc item_options_audit;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| audit_id | int(11) | NO | PRI | NULL | auto_increment |
| option_id | int(11) | YES | | NULL | |
| item_id | int(11) | YES | | NULL | |
| option_name | varchar(100) | YES | | NULL | |
| option_price | int(11) | YES | | NULL | |
| option_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
| change_by | varchar(50) | YES | | NULL | |
| change_date | datetime | YES | | NULL | |
| action | varchar(10) | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
Använd inte främmande nycklar på dina granskningstabeller; raderna i granskningstabellerna är inte underordnade rader till de poster som de granskar, så främmande nycklar är inte till någon nytta.
Triggers
Obs! MySQL stöder inte triggers av flera påståenden, så du behöver en för var och en av INSERT
, UPDATE
och DELETE
(om tillämpligt).
Dina utlösare behöver bara INSERT
alla NEW
värden i granskningstabellen. Triggerdefinitionerna för items
tabellen kan vara:
/* Trigger for INSERT statements on the items table */
CREATE DEFINER=`root`@`localhost` TRIGGER trigger_items_insert_audit
AFTER INSERT ON items
FOR EACH ROW BEGIN
INSERT INTO items_audit (
item_id, item_name, item_description,
item_active, modified_by, change_by,
change_date, action
) VALUES (
NEW.item_id, NEW.item_name, NEW.item_description,
NEW.item_active, NEW.modified_by, USER(),
NOW(), 'INSERT'
);
END;
/* Trigger for UPDATE statements on the items table */
CREATE DEFINER=`root`@`localhost` TRIGGER trigger_items_update_audit
AFTER UPDATE ON items
FOR EACH ROW BEGIN
INSERT INTO items_audit (
item_id, item_name, item_description,
item_active, modified_by, change_by,
change_date, action
) VALUES (
NEW.item_id, NEW.item_name, NEW.item_description,
NEW.item_active, NEW.modified_by, USER(),
NOW(), 'UPDATE'
);
END;
Skapa liknande utlösare för item_options
bord.
Uppdatering:Datahistorik i e-handel
Granskningen vi gjorde ovan gör att du kan behålla en historik över en given databastabell, men skapar ett datalager som inte är lämpligt att använda för data som behöver nås regelbundet.
I ett e-handelssystem, hålla sig användbar historisk data är viktig så att du kan ändra attribut samtidigt som du fortfarande presenterar gamla värden i vissa situationer.
Detta bör vara helt skilt från din revisionslösning
Det bästa sättet att lagra historik är att skapa en historiktabell för varje attribut som måste lagras historiskt. Den här Stackoverflow-frågan har bra information om hur du sparar en historik för ett givet attribut .
I din situation, om du bara är orolig för pris och titel, skulle du skapa en prices
tabell och en item_titles
tabell. Var och en skulle ha en främmande nyckel till antingen item_options
tabellen eller items
tabell (huvudtabellerna skulle fortfarande lagra aktuella pris, eller titel), och skulle ha priset eller titeln, med dess ikraftträdandedatum. Dessa tabeller bör ha finkorniga (eventuellt kolumnbaserade) behörigheter för att undvika uppdatering av effective_from
datum och de faktiska värdena när posten har infogats.
Du bör också använda revisionslösningen ovan på dessa tabeller.