Avatar billede webcreator Nybegynder
11. september 2006 - 13:39 Der er 22 kommentarer og
1 løsning

Isolation level - Serializable

Hej Eksperter.

Jeg forsøger at forhindre læsninger i min database, når jeg skriver til den. Dette skulle være muligt ved at sætte ISOLATION LEVEL til SERIALIZABLE. Dermed skulle alle transaktioner løbe serielt.

Jeg har forsøgt mig med nedenstående eksempel, der sætter isolations-niveauet globalt. Desværre kan jeg stadig læse fra databasen under en transaktion. Jeg tester dette ved at afvikle nedenstående kode i debugging/step-by-step mode, så jeg kan udføre én linje kode af gangen. Når jeg er nået ind i min transaktion har jeg præcis lige så gode muligheder for at læse som jeg havde før jeg startede den.

Gør jeg noget forkert ?

# --------------------------------------------------------------------------------------------------

SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;

# --------------------------------------------------------------------------------------------------

START TRANSACTION;

SELECT @variable := `value` FROM `settings` WHERE `setting` = 'version';
UPDATE `settings` SET `value` = @variable + 1 WHERE `setting` = 'version';

COMMIT;
Avatar billede webcreator Nybegynder
11. september 2006 - 13:42 #1
Ideen er naturligvis at sikre, at jeg ikke kommer til at opdatere på baggrund af forældet data. Hvis vi forestiller os ovenstående kode eksekveret 100 gange samtidig, så er risikoen for at flere transaktioner læser det samme versions-nummer ret stor. Dermed skrives den samme værdi (+1) tilbage til databasen flere gange. Værdien skal incrementeres med 1 HVER gang.
Avatar billede webcreator Nybegynder
11. september 2006 - 13:45 #2
Resultatet af en ikke-seriel eksekvering kunne således se sådan ud (versionsnummer):
1, 2, 3, 4, 4, 4, 5, 5, 6, 7, 8, 9, 9, 10, 10, 10, 10, 10, 11, 12, 13, 14, 15, 15, 15 osv.

En fuldstændig seriel eksekvering vil se således ud :
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 osv.
Avatar billede arne_v Ekspert
11. september 2006 - 14:00 #3
bruger du InnoDB tabeller ?
Avatar billede arne_v Ekspert
11. september 2006 - 14:01 #4
(transaktioner virker ikke i MyISAM tabeller)
Avatar billede webcreator Nybegynder
11. september 2006 - 14:01 #5
Jep :)
Avatar billede webcreator Nybegynder
11. september 2006 - 14:02 #6
Min tabel:

CREATE TABLE `settings`
(
    `setting`        varchar(250),
    `value`            varchar(250),
   
    primary key (`setting`)
) type = InnoDB;
Avatar billede webcreator Nybegynder
11. september 2006 - 14:23 #7
Der er noget der tyder på at gamle forbindelser, der var etableret FØR det nye serialiserings-niveau blev sat, skal reconnectes. Så det prøver jeg lige at lege med.
Avatar billede webcreator Nybegynder
11. september 2006 - 14:40 #8
Ja, det var åbenbart dér problemet lå. Men nu står jeg med et andet problem.

Jeg kan åbenbart starte flere transaktioner samtidig (START TRANSACTION). Og det resulterer i DeadLocks. Jeg havde da forventet at det kørte 100% serielt, og at Applikation 2 måtte vente på, at Applikation 1's transaktion blev færdigt (COMMIT).

Den fejl jeg får :

Error while execeuting query: UPDATE `settings` SET `value` = @variable + 1 WHERE `setting` = 'version':
Deadlock found when trying to get lock; try restarting transaction (errno: 1213)
Click 'Ignore' if you'd like to have this error ignored until the end of the script.
Avatar billede webcreator Nybegynder
11. september 2006 - 14:41 #9
Faktisk ser det ud som om, at transaktionen først bliver opsat i det øjeblik UPDATE statementet eksekveres. Indtil da kan jeg starte nye transaktioner.
Avatar billede arne_v Ekspert
11. september 2006 - 14:46 #10
transaktioner garanterer at operationer ikke generer hinanden

hvis det kan gøres ved at lade noget vente max. X millisekunder så gør den det

hvis ikke så får du en lock error
Avatar billede webcreator Nybegynder
11. september 2006 - 14:53 #11
Okay. Jeg finder det bare underligt at jeg overhovedet får LOV til at starte endnu en transaktion, "parrallelt" med den første.

Faktisk viser det sig, at starter jeg Transaktion 1, og sætter et breakpoint ved UPDATE, og efterfølgende starter Transaktion 2, som får lov at færdiggøre sig, og efterfølgende resume'r Transaktion 1, så får jeg ingen fejl - men Transaktion 1 bliver ikke gemt i databasen.
Avatar billede webcreator Nybegynder
11. september 2006 - 14:55 #12
Men kan denne fejl skyldes tiden det tager mig, at steppe og trykke mig videre igennem mine test cases? For det ville da være rart hvis jeg bare kunne stole på at MySQL gør som den skal, og ikke det som mine tests viser.
Avatar billede arne_v Ekspert
11. september 2006 - 15:08 #13
husk at database transaktioner er beregnet til kortvarige låsninger

man bruger andre metoder, når man f.eks. snakker minutter
Avatar billede webcreator Nybegynder
11. september 2006 - 15:11 #14
Jeg sidder og bliver forvirret nu, for i bogen "Database Systems - A practical approach to Design, Implementation, and Management" beskrives transaktioner i Serializable mode som fuldstændig serielle, mens forfatterne alligevel beskriver forskellige algoritmer til at time transaktioner, så der ikke opstår deadlocks. Men der kan naturligvis være en idé i at time transaktioner, frem for at afvikle alle transaktioner serielt (globalt serializable level). Sidstnævnte må unægteligt reducere samtidigheden hvis der udføres mange transaktioner i systemet.
Avatar billede webcreator Nybegynder
11. september 2006 - 15:12 #15
Men det kan jeg jo passende lige læse på. Mit problem omkring isolations niveauet fandt vi jo ud af. Smid et svar hvis du vil have lidt points :)
Avatar billede arne_v Ekspert
12. september 2006 - 05:12 #16
noget af det smarte ved transaktioner er at de laves så de generer minimalt

selv med serializable, så garanterer den kun at transaktionerne får samme resultat
som hvis de var udført serielt ikke at de faktisk bliver kørt serielt

to transaktioner der ikke berører samme data kan køre fuldt parallelt

derfor kan du selvfølgelig starte en anden transaktion selvom der er en igang
Avatar billede arne_v Ekspert
12. september 2006 - 05:14 #17
der er normal indbygget deadlock checks i database for at undgå situationen
at connection 1 låser række A, connection 2 låser række B, connection 1 venter
så på at få lov til at låse række B, connection 1 venter så på række A

de kan vente meget længe

i det hele taget er transaktioner beregnet til at gå hurtigt - vi snakker
millisekunder
Avatar billede arne_v Ekspert
12. september 2006 - 05:16 #18
Avatar billede arne_v Ekspert
12. september 2006 - 05:16 #19
og et svar
Avatar billede arne_v Ekspert
12. september 2006 - 05:17 #20
det er iøvrigt mest almindeligt at:
  - sætte transaction isolation level for connection i app (ikke globalt)
  - starte og commite transaktioner i app og ikke i SQL
Avatar billede webcreator Nybegynder
12. september 2006 - 13:23 #21
Hej igen.

Tak for de ekstra svar, og referencen til din fine artikel. Mht. isolationsniveauet, så har jeg også ændret det til at være session-baseret. Det kræver SUPER user privilegier at sætte det globalt, og så gælder det for samtlige databaser og forbindelser.

Jeg kan dog undre mig over, at nedenstående variabler alligevel afslører det globale isolationsniveau (REPEATABLE READ), og ikke det som jeg sætter i den aktuelle session (SERIALIZABLE):

SELECT @@global.tx_isolation; // Returnerer "REPEATABLE READ"
SELECT @@tx_isolation; // Returnerer "REPEATABLE READ"
Avatar billede arne_v Ekspert
12. september 2006 - 20:45 #22
jo

men jeg tror at de har lidt problemer

http://bugs.mysql.com/bug.php?id=7955

ikke lige præcis dit problem, men det antyder at de der ting ikke er helt perfekte endnu
Avatar billede webcreator Nybegynder
13. september 2006 - 16:20 #23
Ja, det kan der være noget om. I øvrigt ser det ud til at virke som det skal, selv om tx_isolation indeholder en forkert værdi. Men tak for bug-linket :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester