Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][Doctrine][MySQL] LOCK i UNLOCK
Forum PHP.pl > Forum > PHP
Adi32
Witajcie.

(temat wisiał niespełna dobę w dziale Forum/Bazy danych/MySQL jednak postanowiłem go przenieść tutaj.
Mimo, że jest to mniej odpowiedni temat to w niewielkim stopniu pasuje a jest tutaj większy ruch).

Teoretycznie wszystkiego mógłbym się dowiedzieć chociażby z manuala, googla itp. ale postanowiłem napisać ponieważ przy aktualnym projekcie potrzebuje mieć pewność co do niektórych rzeczy.

Słowo wstępu.
Przeważnie korzystam z Doctrine ORM. Pojawiła się sytuacja, która zmusza mnie do skorzystania z blokowania tabel (przynajmniej tak mi się wydaje) a to co znalazłem w manualu Doctrina na temat blokowania nic mi nie pomogło, dlatego kod nieco się przeplata.

(1) - Zasada działania blokowania tabel...
Muszę w pewniej tabeli wykonać pewne akcie związane z usunięciem starych rekordów i dodaniem nowych. Ważne jest aby w trakcie wykonywania tych akcji nikt nie mógł nawet czytać z tej tabeli a gdyby jednak próbował to najlepiej jakby jego przeglądarka chwileczkę poczekała na zwolnienie blokady.

w tym celu zaprodukowałem taki kod:

  1. # Blokujemy tabele żeby nikt z niej nie czytał gdy będziemy ją przetwarzać
  2. Library_Baza::getInstance()->query("LOCK TABLES test_acl READ");
  3.  
  4. # kasujemy stare dane
  5. Doctrine_Query::create()->delete("TestAcl")->where("id_uzytkownik = $id")->execute();
  6.  
  7. //pre ($for_save);
  8.  
  9. # dodajemy nowe dane
  10. foreach ($for_save as $save) {
  11. $nowy = new TestAcl;
  12. $nowy->id_uzytkownik = $id;
  13. $nowy->fromArray($save);
  14. $nowy->save();
  15. }
  16.  
  17. # odblokowywujemy tabele
  18. Library_Baza::getInstance()->query("UNLOCK TABLES");


Czy jest on w porządku pod każdym względem? Czy spełnia przynajmniej to zadanie o które mi chodzi?

(2) - Dlaczego wykonanie powyższego kodu (testuje go od 3 dni) daje czasami taki efekt, że:
Dosłownie klikam "zapisz" co powoduje wykonanie się tego kodu i od tej pory przeglądarka czeka na odpowiedź z servera nawet kilka godzin? Można odświeżać, usuwać kod itp - nic nie pomaga. Czy dzieje się tak dlatego, że została zablokowana tabela (z której korzysta każda część skryptu) i cały czas czeka na jej odblokowanie?

(opcjonalnie) - Czy mogę ten efekt uzyskać bez przeplatania? Wykorzystując tylko Doctrine?


Miałem jeszcze jakieś pytania ale wyleciały mi z głowy...
uupah5
Cytat(Adi32 @ 6.06.2012, 11:57:24 ) *
Pojawiła się sytuacja, która zmusza mnie do skorzystania z blokowania tabel (przynajmniej tak mi się wydaje)

moim zdaniem źle kombinujesz. istnieje bardzo niewielka szansa, że faktycznie blokowanie tabeli jest w twoim przypadku prawidłowym rozwiązaniem problemu.
ponieważ nie napisałeś nic więcej PO CO robisz blokowanie, skupiając się na JAK to zrobić, to proponuję abyś naświetlił szerzej kontekst.
a jako zadanie domowe;), pogooglaj w tematach:
- transakcje
- blokowanie tabeli a wydajność
- silniki mysql, różnice/zalety
- granularity locking




Adi32
Dziękuję za odpowiedź, już traciłem nadzieję.

Na transakcjach się znam, przynajmniej tak mi się wydaje...
W moim przypadku sprawę wydajności można pominąć, chodzi o jedną małą blokadę w pewniej okoliczności.
Korzystam z silnika InnoDB ze względu na relacyjność. W połączeniu z Doctrinem i warstwą aplikacji "Model" zapytania łączone to sama przyjemność.
Wiem, że z pewnych względów zapytania natywne są lepsze jeżeli chodzi o wydajność ale przy niewielkich projektach różnica jest znikoma, tymbardziej jeżeli stosuje się system cachowania, który mam zamiar wprowadzić.

Trochę zszedłem z tematu także opiszę najpierw o co mi tak na prawdę chodzi.

Postanowiłem zrobić jakiś nowy system ACL w pełni zarządzalny który uwzględniałby wszystkie lokacje i akcje z nimi związane.

Administrator posiada drzewo (mapę strony) dla określonego użytkownika.

Modul
--Controller
----Akcja
------Parametr (opcjonalnie)

I system checkboxów do zaznaczanie czy użytkownik ma posiadać dostęp czy nie.

tabela w bazie jest prosta, zawiera kolumny:

id_uzytkownik, module, controller, action, param

Administrator ma dostęp wszędzie więc wpis wygląda tak:

1,*,*,*,*

Użytkownik który ma wszelkie prawa odnoście strony i może jedynie zajrzeć do panelu administracyjnewgo będzie psoiadał 2 wpisy:

2,index,*,*,*
2,admin,*,-,-

I to już działa ale chciałbym aby tabela była zablokowana w momencie gdy admin zmienia uprawnienia, ponieważ zmiana uprawnień polega na skasowaniu wszystkich wpisów dla danego użytkownika i dodania nowych.

Próbowałem różnych akcji względem tabeli test_acl i rezultat jest taki, że teraz mogę jedynie z niej czytać. Nie mogę w niej nic zmienią ani usunąć nawet z poziomu phpmyadmina. Jak spróbuje to strona się zawiesza - ładuje się, czeka na odpowiedź z serwera aż usune ciasteczka sesji.

Pozdrawiam.
Crozin
1. Używasz Doctrine w wersji 1.x, może już czas na przesiadkę na 2.2/2.3? O ile dobrze pamiętam nowa wersja wspiera blokowanie tabel - ale to tylko taka mała uwaga.
2. W rzeczy samej, może dojść do jakiegoś deadlocka.
3. Tutaj w zupełności wystarczy Ci najzwyklejsza transakcja, z poziomu PDO (nie trzeba się nawet bawić w zmianę poziomu izolacji). Co więcej nie ma potrzeby blokowania użytkownika (tabeli). Po prostu odczyta starą zawartość w momencie gdy nowa jest generowana - jest to przecież jedna z czterech podstawowych cech transakcji (ACID).
4. Czyli ostatecznie (w Doctrine będzie to wyglądało niemal identycznie)
  1. try {
  2. $pdo->beginTransaction();
  3.  
  4. $pdo->query('DELETE ... WHERE user_id = 5;');
  5. $stmt = $pdo->prepare('INSERT ... user_id = 5 ...;');
  6.  
  7. for (...) {
  8. $pdo->execute(array('param1' => 'value', 'param2' => 'value'));
  9. }
  10.  
  11. $pdo->commit();
  12. } catch (...) {
  13. $pdo->rollback();
  14. }
5. Jeżeli użytkownik (user_id#5) wykona zapytanie SELECT, w momencie gdy powyższy kod będzie dopiero na etapie pętli for, zwrócone zostaną wyniki sprzed ustanowienia transakcji, czyli sprzed usunięcia rekordów dot. tego użytkownika.
Adi32
Cytat(Crozin @ 8.06.2012, 10:34:39 ) *
1. Używasz Doctrine w wersji 1.x, może już czas na przesiadkę na 2.2/2.3? O ile dobrze pamiętam nowa wersja wspiera blokowanie tabel - ale to tylko taka mała uwaga.


Korzystałem z Doctrina2 przelotnie (specialnie zaktualizowałem wersję php do nowszej) jednak wykonywanie zapytań było mniej wygodne - spodobała mi sie formuła z Doctrine1. Być może za słabo zapoznałem się z D2?

Cytat(Crozin @ 8.06.2012, 10:34:39 ) *
2. W rzeczy samej, może dojść do jakiegoś deadlocka.

A jak teraz z niego wyjść? W manualu SQL znalazłem różne polecenia i zapytania jednak mam Access Denited przy próbie ich wykonania. Uważam że skoro bez konta roota zrobiłem deadlocka to i powinienem móc go cofnąć...

Cytat(Crozin @ 8.06.2012, 10:34:39 ) *
3. Tutaj w zupełności wystarczy Ci najzwyklejsza transakcja, z poziomu PDO (nie trzeba się nawet bawić w zmianę poziomu izolacji). Co więcej nie ma potrzeby blokowania użytkownika (tabeli). Po prostu odczyta starą zawartość w momencie gdy nowa jest generowana - jest to przecież jedna z czterech podstawowych cech transakcji (ACID).


No faktycznie, masz rację - nie pomyślałem o tym.

Cytat(Crozin @ 8.06.2012, 10:34:39 ) *
4. Czyli ostatecznie (w Doctrine będzie to wyglądało niemal identycznie)
  1. try {
  2. $pdo->beginTransaction();
  3.  
  4. $pdo->query('DELETE ... WHERE user_id = 5;');
  5. $stmt = $pdo->prepare('INSERT ... user_id = 5 ...;');
  6.  
  7. for (...) {
  8. $pdo->execute(array('param1' => 'value', 'param2' => 'value'));
  9. }
  10.  
  11. $pdo->commit();
  12. } catch (...) {
  13. $pdo->rollback();
  14. }
5. Jeżeli użytkownik (user_id#5) wykona zapytanie SELECT, w momencie gdy powyższy kod będzie dopiero na etapie pętli for, zwrócone zostaną wyniki sprzed ustanowienia transakcji, czyli sprzed usunięcia rekordów dot. tego użytkownika.


Dzięki Crozin.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.