sql >> Databasteknik >  >> RDS >> Mysql

Lagra alla dataändringar med alla detaljer (som Stackoverflow)

Jag har funderat på det ett tag nu och kan bara komma på två sätt att göra detta på. Båda kan fungera helt transparenta när de skapas i ett abstrakt datalager/modell.

Det finns förresten en implementering för "versionsbara" tabelldata i ORM-mappningsdoktrinen. Se detta exempel i deras dokument . Kanske passar det dina behov, men det passar inte mina. Det verkar ta bort all historikdata när den ursprungliga posten raderas, vilket gör den inte riktigt säker.

Alternativ A:ha en kopia av varje tabell för att lagra revisionsdata

Låt oss säga att du har en enkel kontakttabell:

CREATE TABLE contact (
    id INT NOT NULL auto_increment,
    name VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    PRIMARY KEY (id)
)

Du skulle skapa en kopia av den tabellen och lägga till revisionsdata:

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

Håll koll på INSERT och UPDATE med AFTER utlösare. För varje ny datarevision i originalet, infoga en kopia av den nya datan i revisionstabellen och ställ in modifierings type ordentligt.

För att logga en DELETE revisionssäkert måste du också infoga en ny rad i historiktabellen! För detta bör du använda en BEFORE DELETE trigga och lagra de senaste värdena innan de raderas. Annars måste du ta bort alla NOT NULL begränsning i historiktabellen också.

Några viktiga anmärkningar angående den här implementeringen

  • För historiktabellen måste du släppa varje UNIQUE KEY (här:PRIMARY KEY ) från revisionstabellen eftersom du kommer att ha samma nyckel flera gånger för varje datarevision.
  • När du ALTER schemat och data i den ursprungliga tabellen via en uppdatering (t.ex. mjukvaruuppdatering) måste du se till att samma data eller schemakorrigeringar tillämpas på historiktabellen och dess data också. Annars kommer du att stöta på problem när du återgår till en äldre version av en rekorduppsättning.
  • I en verklig implementering skulle du vilja veta vilken användare som modifierade data. För att ha den revisionssäkra en användarpost bör aldrig raderas från användartabellen. Du bör bara ställa in kontot inaktiverat med en flagga.
  • Vanligtvis involverar en enskild användaråtgärd mer än en tabell. I en verklig implementering skulle du också behöva hålla reda på vilka ändringar i flera tabeller som hör till en enda användartransaktion och även i vilken ordning. I ett verkligt användningsfall skulle du vilja återställa alla ändringar av en enskild transaktion tillsammans, i omvänd ordning. Det skulle kräva en extra revisionstabell som håller reda på användarna och transaktionerna och har en lös relation till alla dessa individuella revisioner i historiktabellerna.

Fördelar:

  • helt i databasen, oberoende av applikationskoden. (nåja, inte när det är viktigt att spåra användartransaktioner. Det skulle kräva viss logik utanför omfattningen av den enskilda frågan)
  • all data är i sitt ursprungliga format, inga implicita typkonverteringar.
  • bra resultat vid sökning i versionerna
  • enkel återställning. Gör bara en enkel INSERT .. ON DUPLICATE KEY UPDATE .. uttalande på den ursprungliga tabellen, med hjälp av data från revisionen du vill återställa.

Förtjänster:

  • Svårt att implementera manuellt.
  • Svårt (men inte omöjligt) att automatisera när det kommer till databasmigreringar/programuppdateringar.

Som redan nämnts ovan, doktriner versionable gör något liknande.

Alternativ B:ha en central ändringsloggtabell

förord:dålig praxis, visas endast för att illustrera alternativet.

Detta tillvägagångssätt är starkt beroende av applikationslogik, som bör döljas i ett datalager/modell.

Du har en central historiktabell som håller reda på

  • Vem gjorde det
  • när
  • ändra, infoga eller ta bort
  • vilka data
  • i vilket fält
  • av vilken tabell

Liksom i det andra tillvägagångssättet kan du också vilja spåra vilka individuella dataändringar som hör till en enskild användaråtgärd/transaktion och i vilken ordning.

Fördelar:

  • du behöver inte vara synkroniserad med den ursprungliga tabellen när du lägger till fält i en tabell eller skapar en ny tabell. den skalas transparent.

Förtjänster:

  • dålig praxis att använda ett enkelt värde =nyckellager i databasen
  • dåligt sökresultat på grund av implicita typkonverteringar
  • kan försämra applikationens/databasens övergripande prestanda när den centrala historiktabellen blir en flaskhals på grund av skrivlås (detta gäller endast för specifika motorer med tabelllås, t.ex. MyISAM)
  • Det är mycket svårare att implementera återställningar
  • möjliga datakonverteringsfel/precisionsförlust på grund av implicit typkonvertering
  • håller inte reda på ändringar när du direkt kommer åt databasen någonstans i din kod istället för att använda din modell/datalager och glömmer att du i det här fallet måste skriva till revisionsloggen manuellt. Kan vara ett stort problem när du arbetar i ett team med andra programmerare.

Slutsats:

  • Alternativ B kan vara väldigt praktiskt för små appar som en enkel "drop in" när det bara är för att logga ändringar.
  • Om du vill gå tillbaka i tiden och enkelt kunna jämföra skillnaderna mellan historisk revision 123 till revision 125 och/eller återgå till den gamla informationen, sedan Alternativ A är den svåra vägen att gå.


  1. körtidsfel:java.lang.ClassNotFoundException:com.mysql.jdbc.Driver

  2. hur ersätter den accentuerade bokstaven i en varchar2-kolumn i Oracle

  3. Stöder mysqldump en förloppsindikator?

  4. MYSQL installationsproblem