Avatar billede kroning Nybegynder
10. november 2006 - 19:49 Der er 10 kommentarer og
2 løsninger

Database håndtering

Jeg bruger Delphi 7 og MySQL. Jeg har en ide om hvordan det skal laves og har så lavet det sådan men det kunne være rart at høre andres meninger.

Bruger A henter en post og begynder at rette i den, bruger B henter nu samme post og begynder også at rette i denne. Bruger B gemmer posten uden problemer, nu vil bruger A så gemme og jeg har så lavet det sådan at bruger A får besked på at en anden bruger har rettet i posten så derfor kan bruger A´s rettelser ikke gemmes og sådan er det bare, synd for bruger A.
Er det måden at gøre det på eller findes der bedre metoder, det er jo ikke så sandsynligt at 2 eller flere brugere vil rettet i samme post på samme tid.
Jeg syntes ikke om metoden med at låse en post da en post så kan risikere at være låst i lang tid hvis brugeren beslutter sig for at hente en kop kaffe eller lign.
Avatar billede pjotre Praktikant
10. november 2006 - 22:11 #1
Jeg bruger altid denne metode og har brugt det både på pc'ere og på de store mainframes i mange år:
På hvert post er der en versionsnummer. (f.eks. kun 1. karakter lang)
Når posten læses gemmes dette versionsnummer i hukommelsen.
Når der så opdateres, skal den "gamle" post have dette nummer. Hvis ikke, er recorden blevet ændret i mellemtiden.
Alt dette kan laves i den sql-streng som bruges til at opdatere databasen med.
Avatar billede pjotre Praktikant
10. november 2006 - 22:13 #2
Jeg glemte lige at når der opdateres, lægges der 1 til versionsnummeret.
Dvs. Når den læses er den f.eks. 3. Og når der opdateres lægges der en 1.
Avatar billede kroning Nybegynder
10. november 2006 - 22:47 #3
Jeg har lavet det sådan at inden ændringerne gemmes henter jeg posten igen for at checke at versionsnummeret er det samme som i den post jeg skal til at gemme. Hvordan gør du det i en sql-streng?
Avatar billede hrc Mester
13. november 2006 - 09:38 #4
Er dt ikke bare noget i retning af dette her:

  update tabel MinTabel set navn=:navn ... , version = version + 1 where id = :id

En anden løsning er at logge ændringerne i en anden tabel og lade opdateringen tjekke den derfra (tjekke at datoen for sidste opdatering af pågældende record ikke er nyere end datoen for den som brugeren har liggende). Problemet er bare med den slags, at log-filer har det med at blive ret store. Man kan risikere at dræbe ydelsen.

Fordelen er, at man vil kunne se 1-n brugere der har opdateret recorden siden brugeren hentede den:

select l.bruger_id, b.navn, l.dato
  from log l
  join by bruger b on (l.bruger_id = b.id)
  where l.tabel_id >= :tabel_id and l.dato >= :dato
  order by l.dato
Avatar billede hrc Mester
13. november 2006 - 09:39 #5
Selvfølgelig smartest hvis man alligevel har tænkt sig at logge databaseoperationerne.
Avatar billede pjotre Praktikant
13. november 2006 - 18:12 #6
hrc har lige glemt det vigtigste i sql'en til update, nemlig at teste på versionsnummeret:
update tabel MinTabel set navn=:navn ... , version = version + 1 where id = :id and version = gammelversion
Avatar billede kroning Nybegynder
13. november 2006 - 18:17 #7
Men hvis updaten så ikke lykkes så er den eneste måde at finde ud af hvorfor det ikke lykkes vel at hente posten og checke?
Avatar billede pjotre Praktikant
13. november 2006 - 18:43 #8
Jeg bruger en try execcute(sqlstreng), hvor jeg tester på returkoder fra Paradox.
Jeg har ud over dette selvfølgelig check på om det er 1. gang recorden skrives. Hvis dette er tilfældet, skal der jo opdateres med en "insert".
Selve opdateringen har jeg liggende i en function, som jeg bruger ved alle mine opdateringer i hele programmet.
Her logger jeg også fejl, som er alvorlige. Logningen foregår i en almindelig txt fil.
Jeg kører forøvrigt med start, commit og bruger rollback i tilfælde af at der kommer en alvorlig fejl under opdateringen. Det er effektivt og har endnu aldrig svigtet på Paradox.
Jeg har meget store kørsler, hvor jeg kører opkrævninger ud.
Når jeg starter på en kunde, startes en transaction. Når kunden er korrekt afsluttet kører jeg en commit. Herefter tages så fat på næste kunde. Sker der fejl under opdateringerne - og dem er der rigtig mange af- laver jeg en rollback og afslutter programmet. Jeg har derfor altid en database som er ok.
Avatar billede hrc Mester
13. november 2006 - 23:47 #9
Transaktionsstyring er aldrig at fornægte. For det første så er operationerne atomiske, enten det ene eller det andet. Ydermere får man meget bedre ydelse da databaserne ellers laver skjulte begin/commit for hver record der skrives. Det er der tilsyneladende mange der overser. Jeg bruger følgende skelet (i pseudokode):

procedure DoSQL(aQuery : TQuery);
var
  LocalTransaction : boolean;
begin
  LocalTransaction := not aQuery.Database.InTransaction; // Improviserer her...
  if LocalTransaction then
    aQuery.Database.BeginTrans;
  try
    aQuery.SQL.Text := '<script>';
    aQuery.ParamByName('<paramnavn>).AsInteger := xxx
    aQuery.ParamByName('<paramnavn>).AsString := yyy

    aQuery.ExexSql;

    if LocalTransaction then
      aQuery.Database.CommitTrans;
  except
    on e: exception do
    begin
      if LocalTransaction then
        aQuery.Database.RollbackTrans;
      raise;
    end;
  end;
end;

... men nu under MS-SQL er jeg gået over til StoredProcs.
Avatar billede kroning Nybegynder
14. november 2006 - 10:28 #10
Transaktionsstyring lyder jo meget smart og jeg har da også tidligere læst om det og tænkt på at benytte det men indtil nu har jeg aldrig oplevet fejl med MySQL så måske er mine systemer ikke så store og med så mange samtidige brugere at det er nødvendig. Men nu understøtter MySQL jo også StoredProcs så det er måske en bedre løning.
Men tak for indput, jeg kan forstå på det at den metode jeg benytter nu ikke er helt hen i vejert. Smider i nogle svar.
Avatar billede pjotre Praktikant
14. november 2006 - 17:26 #11
Pøj - pøj med opgaven. Pjotr4e
Avatar billede hrc Mester
15. november 2006 - 00:35 #12
Jep - god arbejdslyst
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

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