18. april 2004 - 00:20Der er
26 kommentarer og 1 løsning
lidt forståelse af OleDbTransaction's
Når jeg benytter mig af OleDbConnection.BeginTransaction(), så starter jeg en transaction på selve SQL serveren? Så hvis jeg har to applikationer der tilgår samme database, så kan jeg komme uden om nogle samtidigheds problemer ved at benytte mig af transaktioner, og regulere IsolationLevel efter hvad jeg skal bruge?
Når jeg så læser om de forskellige IsolationLevel's på MSDN får jeg f.eks. ved Serializable afvide: A range lock is placed on the DataSet, preventing other users from updating or inserting rows into the dataset until the transaction is complete.
Og hvis jeg læser om det i dokumentationen til den MS-SQL2000 database jeg bruger, får jeg en lidt anderledes beskrivelse. Men hvis jeg har fattet rigtigt, at dette transaction snask startes på selve SQL serveren, så skal jeg vel regne med beskrivelsen som serveren kommer med, eller er jeg galt på den?
Krav at jeg bruger OleDbProvider for at SQL serveren kan udskiftes let uden ændringer i koden. Nej, ikke direkte modstridende, bare flere restriktioner er nævnt på SQL serveren. Og det der med DataSet's i MSDN's beskrivelse, fik mig til at tro at det måske kun var noget transactions styring, der ikke direkte havde noget med databasen serveren at gøre.
Da jeg blev undervist i Java lærte jeg, at man bare implementeret sin database klasse med et singleton pattern og bankede synchronized på alle metoder der manipulerede med databasen, og alle samtidigheds problemer var løst. Men er problemerne ikke kun løst hvis dette er den eneste klasse der tilgår disse tabeller i databasen, man er vel ikke sikret hvis der er to applikationer der tilgår samme tabeller i databasen. Men ville være det hvis man brugte transactioner? Og er der noget skidt ved at benytte transactioner frem for singleton/lock i c# hvis man ved man er alene om databasen?
singleton og synchronized sikrer mod problemer i flere tråde i samme app. Det kræver at singleton klassen er den eneste som bruger database. Det garanterer ikke mod andre problemer hvis samme app køres flere gange eller andre apps bruger databasen.
Du kan også bruge singleton og lock(this) {} i C# helt tilsvarende.
Hvis din app er helt ene om databasen, så svarer singleton + låsning til transaktion med isolation level serializable og en meget dårlig database server.
En god database server vil tillade transaktioner som ikke konflikter at blive udført parallellt selv med isolation level serializable.
I de fleste tilfælde vil det være sikrere og hurtigere at bruge database transaktioner.
Lige en sidste ting som egentligt ikke har så meget med det at gøre. Men hvis jeg har en Web Service med en række metoder der henter eller manipulere med databasen igennem en database klasse. Så har jeg et multi-tråds miljø?
Jeg forstiller mig af web serveren på en eller anden måde opretter en ny tråd for hver connection der er til Web Servicen. Men hvis jeg har implementeret min database klasse med singleton, og jeg åbner databasen forbindelsen i konstruktøren hvor jeg aldrig lukker den igennem klassen. Betyder det, at jeg aldrig har mere end én connection til databasen, lige meget hvor mange der tilgår min Web Service på samme tid? Eller får hver tråd en helt ny instans af Web Servicen og arbejde med?
Hov, lige en sidste ting.. Transactioner, er det noget alle databaser kan, eller ved at benytte mig af transactioner reducerer jeg antallet af databaser jeg vil kunne benytte, lige som hvis jeg bruger stored procedures?
De fleste database understøtter transaktioner. Eneste lille krølle jeg kan komme i tanke om er at man med MySQL skal brugeg InnoDB tabeller og ikke MyISAM tabeller for at få transaktions support.
De fleste databaser understøtter også stored procedures (dog ikke MySQL endnu). Men der er den komplikation at de er forskelligt implementeret. Du kan ikke bare flytte en stored procedure mellem MS SQLServer og Oracle DB selvom begge supporterer stored procedures.
Jeg havde den (forkerte?) opfattelse af når jeg satte isolationlevel til serializable, som er det højeste niveau, at man faktisk blokkerede for alle andre transaktioner indtil den ens transaktion var fuldført. Men efter at jeg blev spurgt om, hvad præcis det er jeg låser med dette isolation niveau, er jeg blevet i tvivl, og synes ikke jeg kan finde noget information der beskriver det præcist.
Jeg kunne godt forstille mig at, man kun sætter en lås om det data man selv berøre. Dvs. at låsen måske kun er omkring de rækker, i de tabeller man piller ved. I stedet for at låse hele databasen som jeg først havde opfattet.
Hmm, der er et eller andet der ikke står helt klart for mig, ang. hvordan de her transaktioner fungere.
Men som jeg har forstået dette:
Hvis man forstiller sig 2 transaktioner t1 og t2. - t1 startes med Connection.BeginTransaction(IsolationLevel.Serializable) i min c# kode klokken 0:00. - t2 startes på samme måde klokken 0:01. - Fordi t1 er sat til IsolationLevel.Serializable og stadig ikke er afsluttet, kan t2 ikke starte med det samme, og må vente. - Fordi jeg synes, det er helt vildt smart lige at kopiere en floppy disk over på min harddisk før jeg commiter t1 (som jeg antager afslutter t1), tager denne transaktion 5mins. - t2 kan derfor nu først startes klokken 0:05.
Er det rigtigt forstået at jeg har blokeret for t2 i 5minutter? Og hvad er det jeg blokere, hele databasen, kun de tabeller t1 arbejder på, eller kun de rækker t1 arbejder på?
Efter lige at have læst dit svar igennem et par gange.. Mener du så at Serializable betyder at, resultatet af afviklingen af t1 og t2 skal være det samme som at de blev afviklet en af gangen. Men at Serializable ikke er en definition på hvordan præcis databasen håndtere at udføre dette, så det kan variere fra DB til DB, men samme resultat er garanteret.
Hvis jeg nu benytter mig af SELECT @@IDENTITY, i et multiuser/tråd miljø. Så er jeg garanteret, at den indeholder det nummer som jeg jeg har genereret tidligere inde i samme transaktion.
Performance mæssigt, er det en katastrofe at benytte sig af denne høje isolation level tit, eller betyder det ikke så meget?
Det jeg fiskede lidt efter med eksemplet, var bare om jeg totalt blokerede databasen ved at benytte den isolations level, eller om alt andet trafik som egentligt ikke er relateret til min transaktion bare fortsætter urørt.
Hvis du bruger SQLServer 2000 så kan det anbefales at bruge SCOPE_IDENTITY() (forskellen er at den overskrives ikke hvis du kalder en stored procedure som indsætter i en anden tabel).
Ja - højere isolation level sænker performance, så principielt vil man køre med den laveste isolation level som stadig garanterer at ens applikation virker.
En seriøs database bør performe nogenlunde selv med isolation level serializable.
re: @@IDENTITY er connection specifik og giver den sidste identity genererer for connectionen. Uanset transaktion.
Ah det er rigtigt, det har du sagt før.
Men når jeg opretter min connection i konstruktøren på min database klasse, og denne klasse bliver tilgået fra web metoder på min web service. Så er det vel ikke helt utænkeligt at med korrekt timing, så bliver der startet to metoder omkring samme tid, som hvert opretter en ny identity, og at der går kluder i hvilke tal der returneres fra databasen. Jeg benytter selv scope_identity() og SP's til dette, så er vel helt uden om problemet, jeg tænker bare..
Du skal have mange tak for din tålmodighed med alle mine ekstra spørgsmål, Trer og dig har lært mig mange ting om database/c# her på det sidste hehe
Synes godt om
Ny brugerNybegynder
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.