Avatar billede wolker Nybegynder
01. oktober 2002 - 14:15 Der er 15 kommentarer og
2 løsninger

Transaction låser tabel

Hej kan det virkelig passe at når jeg gør således

Begin transaction Opdater
update Kunder set navn = 'Jens' where kundeNr = 10

Hvis jeg så fra en anden klient prøver at åbne Kunde-tabellen, så hænger denne ind til ovenstående transaction er committet er rollback.

Grunden til at jeg spørger, er at jeg er ved at udvikle et klient/server program i Delphi og her oplever jeg at hvis man på den ene klient f.eks. åbner en kunde for at redigerer denne, eller opretter en ny kunde, kan man ikke på de andre klienter åbne kunde-oversigten før end der er sagt ok eller Annuller til den nye kunde.
Jeg vil lige nævne at jeg i Delphi-programmet udfører en explecit Begin transaction, og ved Ok en Commit transaction og ved annuler en rollback, det er nød til at gøre, for ellers skal jeg jo gemme alle de gamle oplysninger i tilfælde af at rettelserne annulleres.

Jeg tænkte at det måske var pga. Delphi der ikke understøttede transaction ordentlig, så jeg prøvede at gøre det samme direkte i Mssql, med samme resultat tabellen bliver låst ind til commit.

Jeg har ikke arbejdet med Mssql før, men jeg har en del års erfaring i Oracle, og her har jeg aldrig haft problem med ovenstående.

Så igen, det kan da ikke passe at Mssql ikke kan håndtere det, der må være et eller andet jeg har overset, det håber jeg virkelig, for ellers skal jeg til at skrive meget om i programmet.

Jeg håber at der er en der hurtig kan svare mig på ovenstående, da jeg er i stor tidsnød mht. deadline.
Avatar billede slash Nybegynder
01. oktober 2002 - 14:20 #1
når der selectes, så prøv "select from tabel with(nolock)"
Avatar billede slash Nybegynder
01. oktober 2002 - 14:31 #2
du kan oxo prøve at køre sp_lock fra query analyzeren - det giver et lille overblik over låse i systemet!

Umiddelbart tyder det på at der er en exclusive lock ved din update trans, og så vidt jeg husker så skal din trans være færdig før exclusive locken bliver til en shared lock!

MEN - locking i sql-server kan være en fæl omgang - jeg vil anbefale at du oxo kigger lidt i sql-server books online..
Avatar billede ocp Nybegynder
01. oktober 2002 - 14:41 #3
Det er altså en dårlig løsning at åbne en transaktion for at kunne fortryde indtastninger. Hvorfor laver du ikke bare en update på samtlige felter når der trykkes OK eller undlader at gøre noget hvis der trykkes Fortryd?

Dvs:

update Kunder
set navn = 'Jens', efternavn = 'Hansen', Adresse = 'Bondegården' where kundeNr = 10
Avatar billede ocp Nybegynder
01. oktober 2002 - 14:41 #4
Det var et svar.
Avatar billede wolker Nybegynder
01. oktober 2002 - 14:55 #5
Ja, det med nolock kan løse problemet ang. andre klienter kan se kunde-oversigten samtidig med at en transaction er startet.

Men det hjælper ikke med hensyn til opdatering, og det er helt nødvendig at der kan rettes i 2, 3 eller flere kunder samtidig.

Ved du positiv om det kan lade sig gøre, jeg tænker her på at jeg jo kan give mig til at læse en masse angående locking, men hvis jeg så om 2 dage finder ud af at det ikke kan lade sig gøre, er de dage jo fuldstændig spildt, så hvis du ved om det kan lade sig gøre eller ej og hvis ja, så kan du sikkert fortælle mig hvad og hvor jeg skal starte med at læse

Så vil jeg ku spare en del tid.

Hvordan kører jeg sp_lock?
og hvis du ku uddybe flg
>Umiddelbart tyder det på at der er en exclusive lock ved din update >trans, og så vidt jeg husker så skal din trans være færdig før exclusive locken bliver til en shared lock!


som sagt kender jeg ikke MsSql
Avatar billede slash Nybegynder
01. oktober 2002 - 15:22 #6
sp_lock kører du fra Query Analyzeren. Er at finde i Enterprise manageren under Tools.

Jeg vil tilslutte mig ocp's svar mht. transactions i dette tilfælde - uden jeg kender kontekst, db design etc. Dropper du trans.'s risikerer du naturligvis at få dirty reads...

Der står en del om locking i books online - bare søg på lock (det er faktisk ret omfattende og vil næsten kræve at man tester samtidig!)

En anden lille biting -> prøv at starte din sql profiler (kan findes i enterpise manageren under Tools) op. Opret en ny trace på din db og konfigurer den til at inkludere "Locks" og andre dom du kunne tænke dig at "logge". Start profileren med din oprettede profil. Arbejde lidt med din app. og du vil kunne få mere info ved at kigge i profileren!
Avatar billede bennytordrup Nybegynder
01. oktober 2002 - 15:24 #7
Dit problem er i bund og grund, at du kører bundet mod databasen. Det siger al min erfaring mig, at det er en f*nd*ns dårlig ide.

Prøv at ændre din indtastningsmetode således, at du selv styrer hent og gem til databasen. Det giver bedre muligheder for at fortryde ændringer. Desværre giver det også mere arbejde med at verificere, at andre ikke har ændret.
Avatar billede wolker Nybegynder
01. oktober 2002 - 17:46 #8
ocp>>
>Hvorfor laver du ikke bare en update på samtlige felter når der trykkes
>OK eller undlader at gøre noget hvis der trykkes Fortryd?
Ja, det burde jeg nok gøre, men det vil jo kræve at jeg skal lave enormt meget om i programmet, da alle mine Forms er bundet op til databasen. For det er vel det du mener, altså at jeg selv skal styre opdateringen af db. Til enkle forme, vil det også være rimelig nem at lave om, men jeg har mange forme med master/detail, og her det jo ikke helt simpel.

benny.tordrup>>
>Dit problem er i bund og grund, at du kører bundet mod databasen. Det
>siger al min erfaring mig, at det er en f*nd*ns dårlig ide.
Her vil jeg ikke gi dig ret, for hvis problemet ikke kan løses uden at jeg skal til at styre alt db opdatering selv, så må det være databasen der er problemet. Det er måske fordi jeg er for godt vant, for i Oracle ville det her slet ikke være et problem (Firmaet hvor jeg arbejder nu, har ikke råd til Oracle desværre)

Men for at vende tilbage til problemet, er det ikke mulig på en eller anden måde at løse det, evt. med dirty read eller lign, for der er ikke ret store chancer for at der vil ske en konflikt, da det ikke er mere end måske 4 samtidige bruger vi snakker om, og derved vil risikoen for at de skulle ændre i de samme data være meget meget minimal, næsten ikke eksisterende.
Avatar billede bennytordrup Nybegynder
01. oktober 2002 - 19:21 #9
Hvordan ser din forespørgsel ud, når du skal hente data?

Hvis du laver transaction på et recordset, hvor du laver select * from tabel uden nogen afgrænsning, vil få få låst alle rækker. Prøv i stedet at starte transaktionen på et recordset med kun en record, nemlig den, du skal have fat i til redigering.

wolker>> Det er ikke databasen, der er problemet, men den kontrol/metode, der bruges til at hente data og binde til UI kontroller. Mine erfaringer kommer fra Visual Basic, og de datasource kontroller, der følger med til VB sucks! Derfor min anbefaling om at køre ubundet.
Avatar billede wolker Nybegynder
01. oktober 2002 - 22:24 #10
benny>
Jeg er ikke helt klar over hvad du mener, i Delphi laver man en start transaktion på connection niveau.
Hvordan vil du gøre det på recordset niveau.

Hvis du ikke kender til Delphi, hvordan kan jeg så gøre ovenstående i MsSql. Så vidt jeg ved, skriver man da

Begin transaction Navn
update Kunder set navn = 'Jens' where kundeNr = 10
update ....

Og det der er galt her, er jo at jeg ikke kan lave en update på en anden kunde, på en anden klient, før ovenstående er committet.

Men hvis jeg kan starte en transaktion der kun gælder/låser den aktuelle record, så vil problemet være løst
Avatar billede bennytordrup Nybegynder
02. oktober 2002 - 00:21 #11
Hvordan med isolation level?
Avatar billede bennytordrup Nybegynder
02. oktober 2002 - 00:36 #12
Du kan give følgende kommando i SQL Server:

set transaction isolation level read uncommitted

Det giver ikke låsning af tabellen.

Til gengæld vil andre brugere kunne se de ændringer, du foretager under transaction!
Avatar billede bennytordrup Nybegynder
02. oktober 2002 - 00:36 #13
Default transaction isolation level for SQL Server er read committed.
Avatar billede wolker Nybegynder
02. oktober 2002 - 02:07 #14
benny>
Jep Isolation level, det var det der sku til, plus lidt omskrivning af programmet bl.a også den med with(nolock).

Nu låser den ikke mere, nu kommer der blot fejl ang. nøgleværdien er ændret hvis der bliver rettet i samme record fra 2 klienter, men den fejl-meddelse må jeg kunne fange i en exception og dermed give en pænerer besked til brugeren. Så det burde ikke give de store problemer, for som sagt vil det være meget meget sjældent at konflikten vil opstå.

Så jeg siger mange tak.

slash du får 50 point for dit svar ang. nolock m.m.
Avatar billede bennytordrup Nybegynder
02. oktober 2002 - 07:44 #15
Styringen omkring kun en brugers redigering af samme post kan klares med et låsningsfelt per post. Den skal du så opdatere selv.

Jeg mener dog, at dit design er dårligt med at begynde en transaktion ved start af redigering og efterfølgende commit/rollback ved ok/cancel. En gylden regel på SQL Server er at holde transaktioner kortest muligt.
Avatar billede wolker Nybegynder
02. oktober 2002 - 11:06 #16
>Jeg mener dog, at dit design er dårligt med at begynde en tran....

Ja det vil jeg godt give dig ret i, men hvordan skal jeg så lave det, når jeg ikke vil styre opdateringen selv, da det jo ikke er helt simpelt at styre opdateringen af en master/detail.

I Oracle er jeg vant til at have bundne felter, hvis man her f.eks har et grid i en form, oprettes de records der er nødvendig, men de bliver ikke fysisk gemt i databasen før der udføres en commit/rollback, og der startes ikke en transaction for at gøre det. Og hvis en anden klient tager fat i samme record og forsøger at rette i den, sker der en exception, som man så selfølgelig fanger og herefter viser en pæn fejlmeddelse. Der er ikke noget med at tabellen bliver låst, man kan altså udføre en select * from .... uden problem.

Og det samme gør sig gældende selv om man bruger en Sql-prompt, hvis man f.eks her eksekverer følgende
update kunder set adresse = '' where kundenr >100,
og man herefter blot lukker sql-vinduet er der ikke sket nogen ændring, der skal udføres en commit før det gemmes.

Så mit spørgsmål er, kan man opnå samme funktionalitet med MsSql, hvis ja hvordan, hvis nej, skal jeg åbenbart vænne mig til at bruge ubundne felter, selv om det er mere bøvlet.
Avatar billede wolker Nybegynder
05. december 2002 - 23:44 #17
Jeg vil lige knytte en kommentar ovenstående.

Jeg har ved hjælp af meget eksperimentering og endnu mere læsning fundet frem til den rigtige løsning.

Og løsningen er BatchUpdate, dvs i Delphi kan man sætte database-komponentet til at den kun opdaterer tabellen hvis der udføres en Tabel.UpdateBatch() (locktype sættes til ltBatchOptimistic), se også hjælpen i Delphi.

Jeg ville blot nævne ovenstående, for at hjælpe andre der får samme problemstilling som jeg fik. Og det kan godt ærge mig at der ikke var bare en der nævnede ordet BatchUpdate, for det ku virkelig ha sparet mig for flere dages arbejde.
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