Avatar billede jakoba Nybegynder
03. april 2007 - 13:11 Der er 6 kommentarer og
1 løsning

en udelelig TestAndSet query i mySQL ?

Problem:
  adskillige processer henter rækker fra en MySQL tabel og behandler dem.
  to processer må ALDRIG tage fat i den samme række
  i rækken er der et felt status med typen enum(parat,igang,ferdig)

Så idet en process tager fat i en række skal der ske 2 ting
1) hent rækkedata fra en række hvor status='parat'
2) opdater rækken i tabellen så status får værdien 'igang'
hvis det ikke lykkes at finde en række der er parat skal processen lægge sig til at dø.

Det kan så gøres med transactions:

mysql_query(      "START TRANSACTION"      );
$rs = mysql_query( "SELECT * FROM mintabel
                        WHERE tilstand='parat'
                        LIMIT 1"              );
if( mysql_numrows( $rs ) == 0 ) {
    mysql_query(  "ROLLBACK"                );
    die( 'jeg er færdig\n' );
   
} else {
    echo 'jeg fandt en ny en at ordne\n';
    mysql_query(  "UPDATE mintabel
                        SET tilstand='igang'
                        WHERE id={$rs['id']}"  );
    mysql_query(  "COMMIT"                    );
}

Men ærlig talt, hvor klumpet skal det være.

Er der ikke en mulighed for en update kommando der samtidig henter de rækker den opdaterer i eller en select der opdaterer et felt i de rækker der hentes. En slags MySQL pendant til den TestAndSet kommando man finder i CPUerne.

mvh JakobA
Avatar billede arne_v Ekspert
03. april 2007 - 15:03 #1
1) transaction sikrer dig kun hvis transaction isolation level er passende hoejt
2) nogle SQL dialekter supporterer SELECT FOR UPDATE
3) muligvis kan nu noejes med kun din UPDATE med en ekstra WHERE betingelse
  (AND tilstand=='parat') hvor du saa tester om antal paavirkede raekker er
  stoerre end 0

NB: har du laest http://www.eksperten.dk/artikler/996 ?
Avatar billede jakoba Nybegynder
03. april 2007 - 20:59 #2
1) jep, og det viser det sig det ikke er. Så det må nok blive write LOCK og UNLOCK på tabellen.
2) Det gør MySQL også, men noget halvhjertet. Iflg. manalen skulle det virke på innoDB tabeller, jeg stoler ikke meget på det.
3) Plus at det vel så også vil medføre en loopback og prøv igen hvis 'rows updated' er 0 (vi ved jo stadig ikke om der er flere startklare rækker)

Så indtil videre ser det ud til det skal være:

mysql_query(        "LOCK TABLES mintabel WRITE" );
$rs = mysql_query( "SELECT * FROM mintabel
                              WHERE tilstand='parat'
                              LIMIT 1"              );
if( mysql_numrows( $rs ) == 0 ) {
    mysql_query(    "UNLOCK TABLES" );
    die( 'jeg er færdig\n' );
} else {
    echo 'jeg fandt en ny en at ordne\n';
    mysql_query(    "UPDATE mintabel
                            SET tilstand='igang'
                            WHERE id=" .mysql_result($rs, 0, 'id' )"  );
    mysql_query(    "UNLOCK TABLES" );
}

det er godtnok en tung lås, men det er ikke nogen vældig befærdet tabel og blokeringstiden måles i milliontedele af den tid behandlingen tager.
Avatar billede erikjacobsen Ekspert
03. april 2007 - 21:04 #3
"....skulle det virke på innoDB tabeller, jeg stoler ikke meget på det."  Det kan du nok roligt gøre. Der er "intet" af det spændende, der virker på myisam-tabeller - ud over at de er hurtige. Med innodb får du en "rigtig" database.  Men som du kvantificerer det, så kan du roligt låse tabellen.
Avatar billede arne_v Ekspert
03. april 2007 - 21:23 #4
re 1)

hvis det er InnoDB kan du jo aendre transaction isolation level

(hvis det er MyISAM saa understoetter den ikke transactions overhovedet)

re 2)

jeg har ikke hoert om deciderede fejl med InnoDB

re 3)

LOCK/UNLOCK kan altid bruges men det er altsaa lidt at jage aender med en Leopard kampvogn
Avatar billede jakoba Nybegynder
04. april 2007 - 16:32 #5
men det er jo så SEJT at køre i kampvogn ;-))

aå jeg bliver ved locksene for nu. Ikke mindst fordi jeg ikke rigtig har DB baggrund nok til at gætte hvad de der 4 'transaction isolation level's egentlig gør :(

Og jeg skal jo også producere lidt.

læg et svar arne.
Avatar billede arne_v Ekspert
04. april 2007 - 17:03 #6
du kan nemt opgoogle nogle gode forklaringer

og et svar fra mig
Avatar billede jakoba Nybegynder
04. april 2007 - 20:29 #7
takker
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