Problemet med mistet opdatering opstår, når to eller flere transaktioner læser de samme data, og opdater dem derefter baseret på deres respektive læsninger. Hvis transaktionerne ikke er korrekt synkroniseret, kan opdateringerne af en transaktion overskrive opdateringerne af en anden, hvilket fører til mistede data. Her er flere foranstaltninger, der kan træffes for at forhindre dette:
1. Låsemekanismer:
* eksklusive låse (skriv låse): Når en transaktion ønsker at opdatere en række, erhverver den en eksklusiv lås på den række. Ingen anden transaktion kan erhverve nogen form for lås (læse eller skrive) på den række, indtil den eksklusive lås er frigivet. Dette sikrer, at kun en transaktion kan ændre rækken til enhver tid.
* delte låse (læs låse): Når en transaktion ønsker at læse en række, erhverver den en delt lås på den række. Flere transaktioner kan indeholde delte låse på den samme række samtidigt. Ingen transaktion kan dog erhverve en eksklusiv lås, mens der er delte låse, der afholdes på den række. Dette forhindrer forfattere i at forstyrre læserne.
* Lås granularitet: Niveauet, hvorpå låse påføres (f.eks. Rækkniveau, side-niveau, tabelniveau, databaseniveau) påvirker samtidighed og ydeevne. Finere-kornet låsning (f.eks. Rækketiveau) tillader mere samtidighed, men har højere overhead, mens grovere-kornet låsning (f.eks. Tabelniveau) reducerer overhead, men begrænser samtidigheden.
2. Concurrency Control Protocols:
* to-fase låsning (2PL): En samtidighedskontrolprotokol, der garanterer serialiserbarhed (og således forhindrer mistede opdateringer). Det har to faser:
* voksende fase: En transaktion kan erhverve låse, men kan ikke frigive dem.
* krympende fase: En transaktion kan frigive låse, men kan ikke erhverve nye.
Strenge to-fase-låsning (Strict 2PL) indeholder alle eksklusive låse indtil slutningen af transaktionen (forpligtelse eller rollback). Dette forhindrer kaskaderende rollbacks (hvor en fiasko i en transaktion kan tvinge andres rollback).
* tidsstempelbestilling (til): Hver transaktion tildeles en unik tidsstempel. Systemet bruger disse tidsstempler for at sikre, at modstridende operationer udføres i rækkefølgen af deres tidsstempler. Hvis en transaktion forsøger at skrive en værdi, der allerede er blevet overskrevet af en transaktion med en senere tidsstempel, afvises skrivningen, og transaktionen rulles tilbage. Denne tilgang undgår deadlocks, men kan føre til sult.
* Optimistisk samtidighedskontrol (OCC): Transaktioner fortsætter uden at erhverve låse. Inden en transaktion forpligter sig, kontrollerer den, om nogen anden transaktion har ændret de data, den har læst. Hvis der er konflikter, rulles transaktionen tilbage. OCC er velegnet til situationer med lav påstand, da rollbacks kan være dyre. Det har typisk tre faser:
* Læs fase: Transaktionen læser data og gemmer dem i et lokalt arbejdsområde.
* Valideringsfase: Systemet kontrollerer, om nogen af de data, der blev læst, er blevet ændret af en anden transaktion, siden den blev læst.
* Skriv fase: Hvis validering er vellykket, anvendes ændringerne til databasen. Ellers rulles transaktionen tilbage.
3. Brug af transaktioner:
* Syreegenskaber: Brug altid transaktioner, og sørg for, at dit databasesystem håndhæver syreegenskaberne (atomicitet, konsistens, isolering, holdbarhed). Egenskaben 'isolering' er afgørende for at forhindre mistede opdateringer.
* Transaktionsisoleringsniveauer: SQL -databaser tilbyder forskellige isoleringsniveauer (f.eks. Læs uforpligtede, læst engagerede, gentagne læsning, serialiserbare). Højere isoleringsniveauer (f.eks. Serialiserbar) giver stærkere garantier mod samtidighedsproblemer som mistede opdateringer, men kan reducere samtidighed og ydeevne. Vælg omhyggeligt det passende isoleringsniveau til din applikations behov. `Serialiserbar 'er den mest restriktive og sikreste, men potentielt langsomst. 'Læs engageret' er en almindelig standard og giver rimelig beskyttelse.
4. Logik på applikationsniveau:
* atomoperationer (sammenlign-og-swap): Nogle databasesystemer og programmeringssprog leverer atomoperationer, der kan bruges til at udføre læse-modify-skrivningsoperationer i et enkelt, udelelige trin. F.eks. Kan "sammenligning-og-swap" (CAS) -operationen atomisk opdaterer en værdi, hvis og kun hvis dens aktuelle værdi matcher en specificeret forventet værdi. Denne tilgang kan undgå behovet for eksplicitte låse i nogle tilfælde.
* optagelsesversionering/optimistisk låsning i applikationen: Applikationen kan indeholde et versionnummer (eller tidsstempel) i de data, den læser. Når du opdaterer dataene, inkluderer applikationen det originale versionnummer. Databasen opdaterer derefter kun rækken, hvis versionnummeret matcher det aktuelle versionnummer i databasen. Hvis versionnumrene ikke stemmer overens, afvises opdateringen, og applikationen skal prøve opdateringen igen. Dette er en anden implementering af den optimistiske samtidighedskontrolstrategi.
* Business Logic -overvejelser: Gennemgå forretningslogikken for at se, om der er måder at undgå read-modify-skrivende operationer helt. Kan du redesigne datamodellen eller processen for at undgå potentialet for mistede opdateringer?
5. Databasedesign:
* Normalisering: En korrekt normaliseret database hjælper med at reducere dataredundans og forbedre datakonsistensen, hvilket indirekte kan hjælpe med at forhindre samtidighedsproblemer.
* passende datatyper: Brug af passende datatyper til dine data kan hjælpe med at forhindre fejl og forbedre ydelsen, hvilket indirekte kan hjælpe med at forhindre samtidighedsproblemer.
eksempel scenarie og løsninger:
Forestil dig to brugere, der prøver at opdatere mængden af et produkt i en lagertabel.
* Bruger A: Læser mængde (f.eks. 10). Bruger A ønsker at sælge 2, så beregner ny mængde som 8.
* Bruger B: Læser mængde (f.eks. 10). Bruger B ønsker at sælge 3, så beregner ny mængde som 7.
* Bruger A: Skriver den nye mængde (8) til databasen.
* Bruger B: Skriver den nye mængde (7) til databasen.
Den endelige mængde i databasen er 7, men den skal være 5 (10 - 2 - 3). Bruger A's opdatering gik tabt.
Her er nogle løsninger til dette scenarie:
* eksklusiv lås: Når enten bruger læser mængden til opdatering, skal du erhverve en eksklusiv lås på produktrækken. Den anden bruger skal vente, indtil låsen er frigivet, før han læser og opdaterer.
* Serialiserbart isoleringsniveau: Indstil transaktionsisoleringsniveauet til serialiserbar. Dette sikrer, at de to transaktioner effektivt serialiseres, hvilket forhindrer dem i at blande sig med hinanden.
* optimistisk låsning (med versionnummer):
1. Når bruger A læser mængden (10), læser de også et versionnummer (f.eks. 1).
2. Bruger A beregner den nye mængde (8) og inkluderer det originale versionnummer (1) i opdateringsopgørelsen.
3.. Databasen opdaterer kun mængden, hvis det aktuelle versionnummer stadig er 1. Opdateringsopgørelsen øger også versionnummeret (f.eks. Til 2).
4. Hvis bruger B forsøger at opdatere, efter at bruger A allerede har begået, vil bruger B's opdatering mislykkes (fordi versionnummeret nu er 2), og de bliver nødt til at læse dataene igen og prøve igen opdateringen.
* atomforøgelse/reduktionsoperation: Brug en databasespecifik atomforøgelse/reduktionsdrift, hvis den er tilgængelig. For eksempel:`Opdater inventar sæt mængde =mængde-2 hvor produkt_id =x` Denne tilgang undgår læse-modify-skrivningssekvensen.
Valg af den rigtige tilgang:
Den bedste tilgang til at forhindre mistede opdateringer afhænger af flere faktorer, herunder:
* Samtidig niveau: Hvor ofte foretages opdateringer til de samme data?
* Krav til præstation: Hvad er det acceptable overhead til samtidighedskontrol?
* Databasesystemfunktioner: Hvilke samtidighedskontrolmekanismer understøttes af databasen?
* Applikationskompleksitet: Hvor kompleks er applikationslogikken, og hvor let kan den ændres?
Omhyggelig overvejelse af disse faktorer vil hjælpe dig med at vælge den mest effektive løsning til din specifikke situation. Brug af en kombination af teknikker er ofte den mest effektive strategi. For eksempel ved hjælp af transaktioner med et passende isoleringsniveau i forbindelse med optimistisk låsning på applikationsniveau.