07. december 2005 - 09:24Der er
22 kommentarer og 1 løsning
Transaction Support
Hej Eksperter.
Jeg undre mig lidt over den måde MySQL håndterer System Transactions på. Lad os tage udgangspunkt i flg. eksempel :
START TRANSACTION; INSERT INTO test.mails VALUES ('test1@microsoft.com', 'haps1@haps.dk', 'Yo - Golf on sunday?', 'Hey Bill. Golf on sunday?', now()); INSERT INTO test.mails VALUES ('test2@microsoft.com', 'haps2@haps.dk', 'Yo - Golf on sunday?', 'Hey Bill. Golf on sunday?', now()); INSERT INTO test.mails VALUES ('test3@microsoft.com', 'haps3@haps.dk', 'Yo - Golf on sunday?', 'Hey Bill. Golf on sunday?', now()); COMMIT;
Som det ses starter jeg en transaktion i starten og committer den i slutningen. Altså burde dataene ikke blive indsat i databsen, hvis jeg fx pludselig afslutter transaktionen efter det 2. INSERT-statement. Men kigger man i tabellem Mails, er både post 1 og 2 blevet indsat. Hvordan kan det være?
Jeg kan ganske fint gå tilbage til sidste konsistent tilstand vha. ROLLBACK - men det burde mig bekendt ikke være nødvendigt! Den skal slet ikke committe data før COMMIT kaldes.
Nu ved jeg i øvrigt godt at der ikke er nogen FOREIGN KEYs der gør, at databasen bliver inkonsistent. Men jeg kan ikke tro at dette er grunden til, at dataene alligevel bliver committet øjeblikkeligt.
Håber nogen af jer har en forklaringen. Enten at "Sådan fungerer MySQL altså bare.." eller "Du har jo også lavet en fejl.." :)
Du har fat i noget af det rigtige, for inden der er lavet en commit, kan du fortryde med rollback. Efter commit, kan du ikke fortryde med rollback. Der er derfor "Sådan fungerer MySQL altså bare..", og vil du tilbage til det oprindelige efter 2. inseret satement, kan du kun gøre det med en rollback.
SQL transaction er ikke færdig før der er udført en commit eller en rollback, så du slutter dermed ikke transactions efter 2. insert, men stopper den bare.
Tak for input. Jeg synes dog det er meget mærkeligt. Ifl. MySQLs egen manual skulle AutoCommit blive deaktiveret når man starter en transaktion - og det bliver den helt klart ikke i mit eksempel, eftersom dataene indsættes i min tabel inden Commit-kaldet.
Hvad angår Rollback, så kunne man jo forestille sig et program som går ned midt i en transaktion (strømmen går til computeren) - så vil rollback ikke blive kaldt, og databasen kommer dermed i en inkonsistent tilstand.
Det har du ret i, at Autocommit er deaktiveret når du starter en transaction, men din transaction er ikke færdigudført før der kommer en commit eller en rollback. Ændringer inden commit bliver først permanente når commit er udført, og har du locks på, så bliver de også først released ved commit. Når du stopper efter 2. insert, så er ændringerne i DB ikke permanente. Da der ikke er kommet en commit, så kan du kun afslutte transaction ved rollback. Nu er ændringerne peremanente, men også i sin oprindelig form.
In short, den eneste måde du kan afslutte en transaction på er ved commit eller rollback.
An active transaction exists only after an SQL START QUERY statement is executed subsequent to executing the SQL START TRANSACTION statement for the same connection as the query. An active transaction must be ended with either an SQL COMMIT TRANSACTION or SQL ROLLBACK TRANSACTION statement before attempting to disconnect from the data source with an SQL DISCONNECT DATASOURCE statement. Otherwise, the disconnect attempt will fail because of the active transaction.
Går strømmen midt i en transaction, bliver den ikke afsluttet, men blot stoppet.
Ok. Er jeg gal på den når jeg siger, at det er ualmindelig uhensigtsmæssigt at MySQL har lavet det sådan? Det kan vel netop, som jeg også beskrev før, give en inkonsistent database ved strøm-afbrydelse midt i en transaktion (?).
Min kære lærer har lige vist mig et eksempel i .NET der gør brug af en indbygget Transaction Klasse. Her indsættes dataene _ikke_ i databasen hvis ikke COMMIT kaldes. Så her ser det ud til at virke som forventet.
Enig, og jeg har bare aldrig tænk på det på denne måde, og har ikke overblik over hvad der sker, skulle strømmen gå til den maskine, som har startet transaktion.
Nu er jeg ikke skarp på .NET, men kunne det ikke tænkes, at .NET ikke skriver noget som helst for efter en commit, ganske som i de gode gamle dage. Du skal huske, at med MySQL, der kører du direkte op mod databasen, og jeg har mistanke om, at det gør du ikke i .NET. Bare en tanke, men din lærer kan måske uddybe. Jeg har også godt af at blive klogere en gang i mellem :-)
det du har set svarer til transaction isolation level read uncommitted
måske kører du med det mens .NET eksemplet bruger f.eks. repeatable read transaction isolation level
og det er ikke nødvendigvis et problem i forbindelse med nedbrud - hvis der når serveren startes op og laver recovery laves en rollback så ender man alligevel i en konsistent tilstand
du burde ikke opleve det du beskriver hvis du seææte isolation level til serializable.
Hvis det din lære har vist dig kørte som en COM+ transaction så vil det alt efter hvordan det var konfigureret kunne have køre med isolation level serializable.
Jo jo, men så skal jeg først lige finde et sted der har de forældede versioner. Dem er der sikkert rigeligt af. Men jeg tror lige jeg vil koncentrere mig om eksamens-løsning frem til på mandag hvor jeg skal op :)
Jeg tror i øvrigt jeg kan udelukke en bug i databasen. Det virker nemlig fint med klassen MySQLTransaction fra MySQLs egen .NET Connector. Og som du selv sagde, arne, så sker der næppe noget "Behind the scene".
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.