Aleksejs Posted March 30, 2010 Report Share Posted March 30, 2010 Es parasti lietās, kur nav nauda iepīta saglabāju visu kolonnu vecās vērtības un tad attiecīgi: UPDATE .... WHERE col1=old_col1 AND col2=old_col2 utt - ja affected rows ir = 1 tad viss kārtībā, ja nav - tātad pa vidu kāds paspējis ātrāk izmainīt. Quote Link to comment Share on other sites More sharing options...
Gints Plivna Posted March 30, 2010 Report Share Posted March 30, 2010 (edited) Pieņemot, ka notiek optimistiskā lokošana Oraclē tas izpaudīsies šādi: Abi requesti nolasa, ka 3.lietotājam nauda ir 400, kamēr neviens no viņiem vēl nav veicis update. Abi pie reizes arī nolasa transakcijas idu šim ierakstam, pieņemsim, ka tas ir 10. Tad abi palielina šo 400 par 100 uz 500 un viens pēc otra pārglabā 400 vietā 500 Nu šitas nevar notikt tāpēc, ka: Pieņemsim, ka pirmais, kurš ir paķēris šo ierakstu palielina summu. Kamēr pirmais nav beidzis transakciju jeb pateicis commit, tikmēr otrais šo ierakstu nedabū labot. Tb otrais var izpildīt savu SQL Update teikumu, bet tas gaida. Un gaida mūžīgi, jeb precīzāk izsakoties līdz pirmais pateiks commit vai rollback. Ja pirmais pasaka commit, tad viņš pie reizes ir palielinājis arī transakcijas id uz 11 un otrais tagad mēģina palielināt naudas ierakstu ar iepriekš nolasīto transakcijas id 10. Tā kā tāda ieraksta nav, tad updeits notiek 0 rindiņām un tu saproti, ka ir ziepes. Savukārt, ja pirmais ir pateicis rollback, t.i., atsaucis transakciju, tad updeits notiks, jo transakcijas id tam ierakstam būs tas pats. Gints Plivna http://datubazes.wordpress.com/ Jā nospiedu pirms vēl pateicu domu līdz galam: Tā kā šī nav Oracle, tad diemžēl es nezinu kā 100% precīzi to risina MySQLā, bet man ir baigās aizdomas, ka to var risināt līdzīgi, vismaz optimistisko lokošanu noteikti var izmantot. Edited March 30, 2010 by Gints Plivna Quote Link to comment Share on other sites More sharing options...
codez Posted March 30, 2010 Author Report Share Posted March 30, 2010 Tas, ko tu raksti ir aptuveni skaidrs, bet tad problēma ir šeit: Tā kā tāda ieraksta nav, tad updeits notiek 0 rindiņām un tu saproti, ka ir ziepes. Ko darīt? Rollbackot visas darbības un vienkārši neizpildīt lietotāja requestu? Vai mēģināt vēlreiz visu to pašu, bet šeit atkal vajadzīgs kaut cik universāls mehānisms kā atkārtot neizdevušās darbības no paša sākuma, jauns read, jauns modify un save. Man gan vairāk simpatizē variants, kad row nolocko pret lasīšanu un nākošais request, ja gadījumā pieprasa tos pašus datus, gaida. Bet nepatīk tas, ka tā lokošana reāli nepieciešama tikai dadījumos, kad dati tiek updeitoti, bet tie ir mazāk par 10%. Quote Link to comment Share on other sites More sharing options...
Gints Plivna Posted March 30, 2010 Report Share Posted March 30, 2010 Ko darīt? Rollbackot visas darbības un vienkārši neizpildīt lietotāja requestu? Es domāju, ka tas ir atkarīgs no konteksta. Ja tas ir automātisks process, kam gadījusies šāda bēda, tad 1kārt - būtu jācenšas automātiskos procesos no šādas bēdas izvairīties ;) , piemēram, atsitot visiem citiem iespēju kaut ko mainīt, kamēr tas izpildās, 2kārt - ja tas nav iespējams (aplikācija 24*7 utml probzas ), tad protams, šai automātiskai procai ar to būtu jātiek galā, iespējams jāsāk konkrētais pārskaitījums no sākuma. Savukārt, ja tā ir forma, kurā lietotājs ir kaut ko mainījis, tad jau neko nevar zināt - jo atkarībā no cita lietotāja veiktajām izmaiņām, tas lietotājs, kuram nesanāca saglabāšana, var vēlēties gan datus pārrakstīt ar jau vienreiz ievadītajām vērtībām, gan varbūt nedarīt neko, gan varbūt savadīt pavisam jaunas vērtības, to nekādi algoritmiski uzzināt nevar. Gints Plivna http://datubazes.wordpress.com/ Quote Link to comment Share on other sites More sharing options...
codez Posted March 30, 2010 Author Report Share Posted March 30, 2010 (edited) Izveidoju nelielu piemēru, lai paspēlētos ar tiem pašiem naudas pārskaitījumiem. tabula users ar laukiem id un m. Ieliekam 3 ūzerus 1|100,2|100,3|100; DROP TABLE IF EXISTS `test12`.`users`; CREATE TABLE `test12`.`users` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `m` int(10) unsigned NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; INSERT INTO `test12`.`users` (m) VALUES (100,100,100); Tālāk 2 faili. Ajax fails uz kuru izsauc requestus un lapa, kura izsauc requestus. test12_ajax.php test12.php piemērā parasts variants, kurā lasīšana notiek ar FOR UPDATE kverija beigās un divās vietās iestarpināts pa sekundei aizture, kas simulē kaut cik vienlaicīgu kveriju izsaukšanu. Kveriji tiek izsaukti vienā transakcijā. Piespiežot "both requests" redzam kā viens no requestiem atpaliek par sekundi, jo pie otrā read viņš gaida kamēr otrs request atbrīvos 3 ūzera rowu. Tālāk var pie selektiem noņemt FOR UPDATE un redzēt kā, uzspiežot "both requests" rodas kļūda un kopējā naudas summa visiem 3 ūzeriem vairs nav 300. Nākošais variants ir pamainīt kas kam sūta (ar variantu ar FOR UPDATE) - šijā gadījumā tiek simulēts, ka 1. sūta 3. un vienlaicīgi 3. sūta 1. test12.php Ko mēs iegūstam. 1. konekcija noloko ūzeri 1 2. konekcija noloko ūzeri 3 pēc sekundes 1. konekcija griežas pie ūzera 3, kurš ir nolokots 2. konekcija griežas pie ūzera 1, kurš ir nolokots, mysql detektē deadlocku un izmet kļūdu "1213:Deadlock found when trying to get lock; try restarting transaction" Tātad pavisam vienkāršās situācija mēs varam nonākt pie tā, ka elementārā veidā nav iespējams izveidot pareizi strādājošu aplikāciju. Ja neizmantos FOR UPDATE, tad būs kļūda aplikācijas loģikā un tā sāks ģenerēt nepareizus datus, ja izmanto FOR UPDATE, tad pat šādā elementārā situācijā varam iegūt deadlock un viena no konekcijām izmet kļūdu, kuras pareizai apstrādei jau būs jābūvē diezgan sarežģīta struktūra, kas pamatīgi sarežģi visu aplikācijas izstrādi. Vispār ir iespējams normāli strādāt ar MYSQL? Edited March 30, 2010 by codez Quote Link to comment Share on other sites More sharing options...
2easy Posted March 30, 2010 Report Share Posted March 30, 2010 (edited) 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 ;) Edited March 30, 2010 by 2easy Quote Link to comment Share on other sites More sharing options...
codez Posted March 30, 2010 Author Report Share Posted March 30, 2010 (edited) šijā gadījumā protams piemērs ir triviāls un 'modify' daļā ir parasta saskaitīšan, ko var viegli realizēt ar SQL, bet reālos piemēros aprēķini ir daudz sarežģītāki un UPDATE tos nevarēs realizēt, tāpēc reāli bez struktūras read->modify->save neiztikt. Bez tam arī ar UPDATE šeit varētu iekrist, piemeram: users id|m 1|10 3|100 transfērojam 2 paralēlos requestos 10 naudas no 1 uz 3, 1.konekcija SELECT m FROM users WHERE id=1 10 2.konekcijas SELECT m FROM users WHERE id=1 10 1.konekcijas requests Pārbauda vai 10>=10, lai izpildītu updeitus 2.konekcijas requests Pārbauda vai 10>=10, lai izpildītu updeitus 1.konekcija UPDATE users SET m=m-10 WHERE id=1; UPDATE users SET m=m+10 WHERE id=3; 2.konekcija UPDATE users SET m=m-10 WHERE id=1; UPDATE users SET m=m+10 WHERE id=3; Beigās users id|m 1|-10 2|120 Edited March 30, 2010 by codez Quote Link to comment Share on other sites More sharing options...
2easy Posted March 30, 2010 Report Share Posted March 30, 2010 (edited) nju re, īstā applikācijas sarežģītība neslēpjas ne pp, ne oop, bet out there... tobish pašos algoritmos, nevis kkādās paradigmās ;) principā ja ir kkas sarežģīts, tad sasniegums jau ir tad, kad vsp izdodas to piedabūt, lai tas pareizi strādā. un tad ir pofig, cik tas ir neērti/neefektīvi/nepareizi/nesmuki/... kr4 visas ambīcijas par optimizēšanu var pieturēt kādai citai reizei :P Edited March 30, 2010 by 2easy Quote Link to comment Share on other sites More sharing options...
2easy Posted March 30, 2010 Report Share Posted March 30, 2010 (edited) 1.konekcijas requests Pārbauda vai 10>=10, lai izpildītu updeitus 2.konekcijas requests Pārbauda vai 10>=10, lai izpildītu updeitus jā, jā, jā, tāds gudrinieks! ;) šīs pārbaudes taču ir jāliek sql WHERE daļā (kā tehnisks check), nevis kkur applikācijas loģikā tipa šādi UPDATE users SET m=m-10 WHERE id=1 AND m >= 10 vsp šādos gadījumos Ginta ieteiktā update menedžēšana, izmantojot transakcijas id kolonnu, realy makes sense. malacis Gint. labs ieteikums. bet tā jau laikam ir diezgan izplatīta/standarta prakse. tikai mēs te web developeri līdz tik sarežģītām lietām ne vnm nonākam... :D:D:D Edited March 30, 2010 by 2easy Quote Link to comment Share on other sites More sharing options...
codez Posted March 30, 2010 Author Report Share Posted March 30, 2010 (edited) Pag,pag ir ne tikai userim 1 jāsamazina par 10, bet arī userim 3 jāpalielina par 10. Pamēģini uzrakstīt to vienā kverijā. Un kāpēc jāizmanto transakcija kollona, ja tiek izmantots jau iebūvētais transakciju mehānisms, ko piedāvā innodb dzinējs Edited March 30, 2010 by codez Quote Link to comment Share on other sites More sharing options...
2easy Posted March 30, 2010 Report Share Posted March 30, 2010 Pag,pag ir ne tikai userim 1 jāsamazina par 10, bet arī userim 3 jāpalielina par 10. Pamēģini uzrakstīt to vienā kverijā. pēc pirmā update if (mysql_affected_rows()) ... // un tad tikai izpilda otro update Un kāpēc jāizmanto transakcija kollona, ja tiek izmantots jau iebūvētais transakciju mehānisms, ko piedāvā innodb dzinējs ok, lai nebrauktu dziļāk auzās, par šo labāk paklusēšu :D:D:D bet anyway man patika Ginta lekcija ;) Quote Link to comment Share on other sites More sharing options...
mounkuls Posted March 30, 2010 Report Share Posted March 30, 2010 Nu nezinu, es lasiju, lasiju, domas visādas pa galvu maisās. Bet vai tur ko reāli maz var iegūt, ja to visu tā pat vajag sagremot uz servera un tad tikai SQL prasīt ko vēlas? Quote Link to comment Share on other sites More sharing options...
2easy Posted March 30, 2010 Report Share Posted March 30, 2010 uzraksti labāk kādu dzejoli vai slavas dziesmu par šo sarežģīto tēmu. tā ir tā vērta! es domāju tev labi sanāks. ar visām atskaņām :D Quote Link to comment Share on other sites More sharing options...
mounkuls Posted March 30, 2010 Report Share Posted March 30, 2010 Vērta vai ne, es nezinu, bet kāda jēga dračīt ajax pa sekundei, ja tā pat to sagremos vienā vietā. Vēl lauzīt galvu kā optimizēt kveriju, ja iespēja ir potenciāli arī iebraukt auzās, īsti man saprotami nav. Es neesmu nekāds spečuks, bet nav tā kā par sasālīts tas viss? Quote Link to comment Share on other sites More sharing options...
2easy Posted March 30, 2010 Report Share Posted March 30, 2010 codez tur taisa kko krutu. ne jau viss ir tik vnkārši kā echo 'mana lapa :D'; 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.