sql >> Database teknologi >  >> RDS >> Mysql

Revisionslogning for produktdata?

Dine revisionsdata skal gemmes pr. tabel i stedet for alle på ét sted. Det, du skal gøre, er at oprette en revisionstabel for hver af de tabeller, du vil spore, og oprette triggere for at oprette en post i revisionstabellen for enhver datamanipulationshandling på den reviderede tabel.

Det er absolut tilrådeligt at afvise DELETE handlinger på items og item_options tabeller - tilføj flag som item_active og item_option_active så du kan softdelete dem i stedet for. Dette er normal praksis i situationer, hvor du gør ting som at gemme fakturaer, der refererer til produkter, der er bestilt i fortiden, og har brug for dataene til historiske rapporteringsformål, men ikke til daglig brug.

Dine revisionstabeller er ikke noget, du skal bruge til at referere til gamle data, din normale datamodel skal understøtte blot at "skjule" gamle data, hvor det er sandsynligt, at det stadig vil blive brugt, og gemme flere versioner af data, der vil ændre sig over tid.

Til revision er det også nyttigt at gemme brugernavnet på den sidste bruger til at ændre en given post - når det bruges fra en webapplikation, kan du ikke bruge MySQL's USER() funktion for at få brugbar information om, hvem der er logget på. Tilføjelse af en kolonne og udfyldning af den betyder, at du kan bruge disse oplysninger i dine revisionstriggere.

NB: Jeg går ud fra, at du ikke vil tillade, at vare-id'er ændres under normale forhold - det ville gøre dit revisionssystem mere komplekst.

Hvis du tilføjer aktive flag og sidst ændrede data til dine tabeller, vil de se nogenlunde sådan ud:

Tabel med elementer:

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    |                |
+------------------+--------------+------+-----+---------+----------------+

Tabel med vareindstillinger:

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    |                |
+---------------+--------------+------+-----+---------+----------------+

Dine revisionstabeller skal gemme fire ekstra stykker information:

  • Revisions-id - dette id er kun unikt for historien om dette tabel, er det ikke en global værdi
  • Ændring foretaget af - databasebrugeren, der foretog ændringen
  • Skift dato/klokkeslæt
  • Handlingstype - INSERT eller UPDATE (eller DELETE hvis du tillod det)

Dine revisionstabeller skal se nogenlunde sådan ud:

Revisionstabel for elementer:

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    |                |
+------------------+--------------+------+-----+---------+----------------+

Revisionstabel for vareindstillinger:

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    |                |
+---------------+--------------+------+-----+---------+----------------+

Brug ikke fremmednøgler på dine revisionstabeller; rækkerne i revisionstabellerne er ikke underordnede rækker af de poster, de reviderer, så fremmednøgler er ikke til nogen nytte.

Udløsere

NB: MySQL understøtter ikke triggere af flere sætninger, så du skal bruge en for hver af INSERT , UPDATE og DELETE (hvis relevant).

Dine triggere skal blot INSERT alt det NEW værdier i revisionstabellen. Udløserdefinitionerne for items tabellen kan være:

/* 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;

Opret lignende triggere for item_options tabel.

Opdatering:Datahistorik i e-handel

Den revision, vi foretog ovenfor, giver dig mulighed for at opbevare en historik for enhver given databasetabel, men skaber et datalager, der ikke er egnet til brug for data, der skal tilgås regelmæssigt.

I et e-handelssystem holdes brugelig historiske data er vigtige, så du kan ændre attributter, mens du stadig præsenterer gamle værdier i visse situationer.

Dette bør være fuldstændig adskilt fra din revisionsløsning

Den bedste måde at gemme historik på er at oprette en historiktabel for hver attribut som skal opbevares historisk. Dette Stackoverflow-spørgsmål har nogle gode oplysninger om at opbevare en historik for en given egenskab .

I din situation, hvis du kun er bekymret for pris og titel, ville du oprette en prices tabel og en item_titles bord. Hver enkelt vil have en fremmednøgle til enten item_options tabellen eller items tabel (mastertabellerne ville stadig gemme den aktuelle pris eller titel), og vil have prisen eller titlen med dens ikrafttrædelsesdatoer. Disse tabeller bør have finkornede (muligvis kolonnebaserede) tilladelser for at undgå opdatering af effective_from datoer og de faktiske værdier, når posten er indsat.

Du bør også bruge revisionsløsningen ovenfor på disse tabeller.



  1. Sådan får du den aktuelle dato i SQLite

  2. Brug af IS NULL og COALESCE i OrderBy Doctrine Querybuilder

  3. Hvorfor overhovedet bruge *DB.exec() eller forberedte sætninger i Golang?

  4. Tæl fortløbende duplikerede værdier i SQL