Aleksejs Posted March 31, 2010 Report Share Posted March 31, 2010 Varbūt noder lasāmviela: Introduction to Transaction Control Nuts and Bolts of transaction processing Quote Link to comment Share on other sites More sharing options...
codez Posted March 31, 2010 Author Report Share Posted March 31, 2010 (edited) 2easy, Tak nav tur nekas kruts, vienkārš piemērs, kuram neredzu pagaidām vienkāršu risinājumu, kurš strādātu 100% pareizi. 2easy, nekoncentrējies tik daudz uz to, lai atrisinātu konkrēto piemēru ar kādu workaroundu, bet gan koncentrējies uz pašu ideju, ka ir nepieciešam realizēt šādu mehānismu: 1)nolasa datus no db 2)php veic aprēķinus 3)saglabā datus db un izmantojot šo vienkāršo piemēru, pamēģini realizēt šo read->modify->save struktūru tā, lai tā strādātu 100% pareizi. Pagaidām visoptimistiskākais risinājumus, kurš dotu 100% pareizu darbību ir izmantot FOR UPDATE un ķert deadlockus, kuru gadījumā mēģināt realizēt to, lai cikls read->modify->save sāktos no jauna, bet tas nešķiet pagaidām tik vienkārši, jo principā programma jau atrodas pusceļā, kaut kādi mainīgie jau ir inicializēti, kaut kādas struktūras izveidotas un katrā gadījumā smalki pētīt vai atgriežoties sākumā esi pareizi visu reinicializējis ir pasmags darbs, jo vienā aplikācijā šādi read->modify->save cikli ir desmitiem, tāpēc vajag radīt kaut cik universālu un elastīgu šo atgriešanās sākumā mehānismu, ko es tagad arī cenšos izdarīt. Vai arī atrast citu risinājumu, kā read->modify->save ciklu realizēt 100% pareizi. Edited March 31, 2010 by codez Quote Link to comment Share on other sites More sharing options...
mickys Posted March 31, 2010 Report Share Posted March 31, 2010 lieto nevis absolūto set, bet relatīvo increment UPDATE test12 SET m = m + 100 WHERE id = 1 tad vari kaut vai 10x vienlaicīgus update taisīt un beigās tik un tā būs +1000 :)) kkad pasen lasīju, kā šādi iztikt vsp bez lokošanas ;) Ieinteresēja. Vai tiešām šāda darbība tāpat konkrētajā gadījumā izsauc kļūdu un ir nepieciešamas transakcijas? Quote Link to comment Share on other sites More sharing options...
codez Posted March 31, 2010 Author Report Share Posted March 31, 2010 (edited) Nē nav nepieciešamas, jo šī darbība ir atomic darbība un veic read->modify->save ciklu tā, ka neviena cita darbība pa vidu neispraucas. Edited March 31, 2010 by codez Quote Link to comment Share on other sites More sharing options...
2easy Posted March 31, 2010 Report Share Posted March 31, 2010 (edited) vajag radīt kaut cik universālu un elastīgu šo atgriešanās sākumā mehānismu, ko es tagad arī cenšos izdarīt. Vai arī atrast citu risinājumu, kā read->modify->save ciklu realizēt 100% pareizi. kad atrodi labu risinājumu, noteikti šeit ieposto ;) good luck Edited March 31, 2010 by 2easy Quote Link to comment Share on other sites More sharing options...
codez Posted March 31, 2010 Author Report Share Posted March 31, 2010 (edited) Šeit viens no risinājumiem kā apstrādāt deadlockus: test12.php test12_ajax.php 1)tika izveidots deadlockexceptions class DeadlockException extends Exception{ } 2)db klasē pie kveriju izpildes, ja kverijs neizdevās un kļūda no ir 1213 (deadlock) izmetam DeadlockException function q($s){ if (!$res=$this->query($s)) { if ($this->errno==1213) { $this->deadlocks++; throw new DeadlockException(''); } else { die($this->errno.':'.$this->error); } } return $res; } 3)Visu transakciju lieka try cahce, kuru savukārt liekam while ciklā, kurš testē vai transakcija veiksmīgi pabeigta. Parediģējam arī commit metodi, kurā pievienojam, ka veiksmīgas šīs metodes izsaukšanas gadījumā, deadlock nomainam uz false; Tāpat pie cache notestējam vai nav sasniegts maksimālais deadlocku skaits <- šo gan varētu pārmest testēt DB klasē vietā, kura palielina deadlocku skaitu un attiecīgi deadlock exception izmešanas vietā pie pārsniegta skaita, pārtraukt requestu vispār. $db->startTransaction(); while ($db->isDeadlock()){ try { $m1=$db->q1("SELECT m FROM users where id=$fromid FOR UPDATE"); sleep(1); $m2=$db->q1("SELECT m FROM users where id=$toid FOR UPDATE"); echo "user $fromid: $m1\n"; echo "user $toid: $m2\n"; $m1-=1; $m2+=1; sleep(1); $db->query("UPDATE users SET m=$m1 WHERE id=$fromid"); $db->query("UPDATE users SET m=$m2 WHERE id=$toid"); $db->commit(); } catch (DeadlockException $e) { if($db->isMaxDeadlocks()) { $db->noDeadlocks; //šeit attiecīgi izdomājam ko darīt, ja sasniegts maksimālais deadlocku skaits. //normālā darbībā šim nevajadzētu izsaukties } } } EDIT: šeit variants, kad max_deadlocks apstrādā pašā DB klasē, to sasniegšanas gadījumā pārtrauc requestu: test12_ajax.php Katrā gadījumā, testējot piemēru var redzēt, kā viens no requestiem izpildās 2 sekundēs, bet otrs trijās, jo pēc pirmā sleep nonāk deadlockā un sāk visu transakciju no jauna. Tāpat arī baigās var redzēt, ka otrajam requestam ir viens deadlocks. Edited March 31, 2010 by codez Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.