Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Znajomosci userow - Transakcje + blokowanie tabel (MySQL + php)
Forum PHP.pl > Forum > Bazy danych > MySQL
MiGoo
Witam! Chcialem sie poradzic pewnej kwestii, gdyz nie wiem do konca czy napisalem kod dobrze. Sytuacja jest nastepujaca:


Mam tabele z userami (MySQL):

  1. CREATE TABLE `users` (
  2. `u_id` bigint(20) NOT NULL AUTO_INCREMENT,
  3. `u_login` varchar(100) NOT NULL DEFAULT '',
  4. `u_haslo` varchar(34) NOT NULL DEFAULT '',
  5. `u_nick` varchar(40) DEFAULT NULL,
  6. `u_znajomi` longtext DEFAULT NULL,
  7. `u_aktywny` int(1) NOT NULL DEFAULT '1',
  8. PRIMARY KEY (`u_id`),
  9. UNIQUE KEY `u_login` (`u_login`),
  10. ) TYPE=InnoDB AUTO_INCREMENT=4 ;
  11.  
  12. INSERT INTO `users` VALUES (1, 'login1', 'd4b21940e8f49a14903e6310e8cd14f4', 'nick1', 'a:1:{i:0;i:3;}',1);
  13. INSERT INTO `users` VALUES (2, 'login2', 'd4b21940e8f49a14903e6310e8cd14f4', 'nick2', 'a:1:{i:0;i:3;}',1);
  14. INSERT INTO `users` VALUES (3, 'login3', 'd4b21940e8f49a14903e6310e8cd14f4', 'nick3', 'a:2:{i:0;i:1;i:1;i:2;}',1);



Pole u_znajomi zawiera informacje o tym, kto jest znajomym danego usera (w postaci tablicy, zapisywanej w formie
zserializowanej). User login3 ma zatem znajomych: login1 i login2, a userzy login1 i login2 maja zapisanego: login3.
Najwazniejsza rzecz jest tutaj taka, ze jesli jeden user ma zapisanego znajomego, to ten znajomy musi miec w znajomych
tez tego usera - nie moze byc tak, ze jeden ma zapisanego jakiegos, a ten drugi nie ma o tym userze informacji.

Pole u_aktywny - jesli ma wartosc 1 - user jest aktywny w serwisie

Jezeli jakis user chce byc czyims znajomym, zaprasza go (po akceptacji zostaje znajomym). Informacja o zaproszeniach
zapisana jest w tabeli:

  1. CREATE TABLE `zaproszenia` (
  2. `z_id` bigint(20) NOT NULL AUTO_INCREMENT,
  3. `u1_id` bigint(20) NOT NULL DEFAULT '0',
  4. `u2_id` bigint(20) NOT NULL DEFAULT '0',
  5. `z_data` int(10) NOT NULL DEFAULT '0',
  6. PRIMARY KEY (`z_id`),
  7. KEY `u1_id` (`u1_id`),
  8. KEY `u2_id` (`u2_id`),
  9. KEY `z_data` (`z_data`)
  10. ) TYPE=InnoDB AUTO_INCREMENT=2 ;


gdzie: u1_id - id usera wysylajacego zaproszenie (w kodzie php - $id1)
u2_id - id usera zapraszanego ($id2)

Zalozmy ze user login1 wyslal zaproszenie do login2 (jesli sa juz znajomymi, to nie mozna wyslac zaproszenia, wyswietlam
info, ze sa juz znajomymi). Zatem w tabeli zaproszenia mamy rekord:

  1. INSERT INTO `zaproszenia` VALUES (1, 1, 2, 1149851150);


I teraz user login2 chce zaakceptowac zaproszenie, zatem $id1=1; $id2=2;
Kod w php realizujacy akceptacje zaproszenia jest nastepujacy:

  1. <?php
  2. $core->query ("SET AUTOCOMMIT=0"); // $core->query - moja funkcja wykonujaca zapytania MySQL'a
  3. $core->query ("BEGIN"); // poczatek transakcji - dzialamy na dwoch tabelach
  4. $core->query ("LOCK TABLES users WRITE, zaproszenia WRITE"); // blokuje tabele, by miec pewnosc, ze w miedzy
  5. // czasie nie akceptuje zaproszenia, lub go nie usuwa - w koncu moze otworzyc strone w wielu przegladarkach
  6.  
  7. $blad=0;
  8.  
  9. $core->query ("DELETE FROM zaproszenia WHERE u1_id=".$id1." AND u2_id=".$id2); // usuwam zaproszenie
  10. if (mysql_affected_rows()!=1) $blad++;  // blad => zaproszenie nie istnieje
  11.  
  12. if ($blad==0)
  13. {
  14. $core->query ("SELECT u_znajomi FROM users WHERE u_id=".$id2." LIMIT 1");
  15. $znajomi1=$core->query_result[0]['u_znajomi']; // znajomi usera, ktory akceptuje zaproszenie
  16. if ($znajomi1!=NULL)
  17. {
  18. $znajomi1=unserialize ($znajomi1);
  19. if (!in_array ($id1,$znajomi1)) $znajomi1[]=$id1; // zapisuje, jesli user nie byl znajomym, jesli byl, to w ogole nie mozna wyslac z
    aproszenia
  20. }
  21. else $znajomi1[]=$id1;
  22. $znajomi1=serialize ($znajomi1);
  23.  
  24. $core->query ("SELECT u_aktywny, u_znajomi FROM users WHERE u_id=".$id1." LIMIT 1");
  25. if ($core->query_result[0]['u_aktywny']!=1) // nie ma juz usera, ktory zapraszal => mozna usunac zaproszenie
  26. // kod ponizej: odblokowujemy tabele, i wyswietlamy strone informacyjna
  27. { $core->query ("COMMIT"); $core->query ("UNLOCK TABLES"); header ("Location: index.php?info=4"); exit; }
  28.  
  29. $znajomi2=$core->query_result[0]['u_znajomi']; // znajomi usera, ktory zapraszal => istnieje dalej w serwisie
  30. if ($znajomi2!=NULL)
  31. {
  32. $znajomi2=unserialize ($znajomi2);
  33. if (!in_array ($id2,$znajomi2)) $znajomi2[]=$id2;
  34. }
  35. else $znajomi2[]=$id2;
  36. $znajomi2=serialize ($znajomi2);
  37.  
  38. $core->query ("UPDATE users SET u_znajomi='".$znajomi1."' WHERE u_id=".$id2); // update znajomych usera, ktory akceptuje zaproszenie
  39. if (mysql_affected_rows()!=1) $blad++; // musi byc przetworzony jeden wiersz, bo wiemy, ze nie byli znajomymi
  40. }
  41.  
  42. if ($blad==0)
  43. {
  44. $core->query ("UPDATE ".$core->prefix."_users SET u_znajomi='".$znajomi2."' WHERE u_id=".$id1);
  45. if (mysql_affected_rows()!=1) $blad++;
  46. }
  47.  
  48. if ($blad>0)
  49. {
  50. $core->query ("ROLLBACK");  // odrzucenie
  51. $core->query ("UNLOCK TABLES");
  52. header ("Location: index.php?info=4");
  53. }
  54. else
  55. {
  56. $core->query ("COMMIT");  // akceptacja
  57. $core->query ("UNLOCK TABLES");
  58. header ("Location: index.php?info=3");
  59. }
  60. }
  61. ?>


I teraz pytanie: czy powyzsze rozwiazanie problemu znajomosci userow jest dobre? Tzn. czy zapewnione sa warunki:
- w czasie dzialania skryptu userzy nie usuna zaproszenia (bo moga w osobnym miejscu)
- na pewno u obydwoch userow zostanie zapisana informacja o znajomych - czyli u zapraszanego id usera, ktory go zapraszal, a u tego co zapraszal id usera zapraszanego

Pytania sa trywialne i raczej nie powinienem ich zadawac, lecz zdarzylo mi sie raz tak, ze jeden user (powiedzmy o id 5) ma zapisana informacje o znajomosci z userem (np. 6), lecz user 6 nie ma infa o nr 5...

Moze nie powinienem uzywac blokad tabel skoro mam transakcje? Prosze o pomoc smile.gif
orson
witam

jeżeli są transakcje oraz silnik bazy _wspiera_ transakcje (tylko innodb ! w mysql - przy myisam są one tylko w celach kompatybilnościowych - ich użycie nie daje spodziewanego efektu) to nie musisz dodawać locka - aplikacja będzie wydajniejsza ... ponad to wyciągnął bym dane o znajomych do osobnej tablicy zamiast do serializowanej w rekordzie - ułatwia to ogromnie wyszukiwanie ...

nie bardzo mi się chce analizować/odpalać ten kod (dopiero co z pracy wróciłem) ale trochę mi się wydaje że to dużo kodu jak na dosyć prostą operację ... gdybyś miał w osobnej tablicy z FK to całość skróciła by się do 2-3 zapytań ... jeżeli używasz takich właściwości tabel jak transakcje oraz lock użyj też innych jak FK, SP lub UDF ... przeniesienie dużej ilości operacji na silnik bazy bardzo ułatwia pisanie ...

pozdrawiam
MiGoo
Cytat(orson @ 5.07.2006, 19:23 ) *
witam

jeżeli są transakcje oraz silnik bazy _wspiera_ transakcje (tylko innodb ! w mysql - przy myisam są one tylko w celach kompatybilnościowych - ich użycie nie daje spodziewanego efektu) to nie musisz dodawać locka - aplikacja będzie wydajniejsza ...


Oczywiście stosuję InnoDB - ale jeśli wyrzucę blokowanie tabel, to czy transakcja je zablokuje? Bo jesli w miedzyczasie ktos innny będzie akceptował powiedzmy usera nr 1, a user nr 1 jeszcze kogos innego, to musi byc jakaś blokada, by wszystkie zmiany zostały w bazie zachowane... Transakcje dają mi tą gwarancję? I skąd transakcja wie, które tabele zablokować?


Cytat(orson @ 5.07.2006, 19:23 ) *
ponad to wyciągnął bym dane o znajomych do osobnej tablicy zamiast do serializowanej w rekordzie - ułatwia to ogromnie wyszukiwanie ...


No tak tez myslalem, ale stwierdzilem, ze taka tabela bedzie zbyt duza i zrobilem to w opisany wyzej sposob. Gdyby znajomosci byly w osobnej tabeli, to kazda znajomosc mialaby jeden rekord, co powodowaloby, ze bardzo szybko roslaby w niej ilosc rekordow... Np. jesli user mialby 20 znajomych, to juz jest 20 rekordow... Dlatego zrobilem to jak zrobilem. Chyba ze mozna to inaczej zrobic - niestety nie mam pomyslu...


Cytat(orson @ 5.07.2006, 19:23 ) *
nie bardzo mi się chce analizować/odpalać ten kod (dopiero co z pracy wróciłem) ale trochę mi się wydaje że to dużo kodu jak na dosyć prostą operację ... gdybyś miał w osobnej tablicy z FK to całość skróciła by się do 2-3 zapytań ... jeżeli używasz takich właściwości tabel jak transakcje oraz lock użyj też innych jak FK, SP lub UDF ... przeniesienie dużej ilości operacji na silnik bazy bardzo ułatwia pisanie ...

pozdrawiam


A mozna prosic o jakis przykladowy kod z uzyciem osobnej tabeli i kluczy obcych?

Jednak po kolejnym, gruntownym przemysleniu sprawy stwierdzilem, ze jednak osobna tabela bedzie najlepszym rozwiazaniem... Temat do zamkniecia smile.gif
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.