Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Błąd zapytań w tym samym czasie
Forum PHP.pl > Forum > Bazy danych > MySQL
shycat
Witam, mam takie dwie tabele w bazie danych:


tabela "dane"
ilsoc_userow int
...

tabela "uzytkownicy"
id_usera int (PRIMARY KEY)
....


Podczas zakladania nowego konta (wpis przez INSERT) calosc dziala w ten sposob:

pobierz ilosc userow -> $ilosc=ilosc_userow+1 -> zapisz ilosc userow w "dane" -> utworz przez INSERT wpis w "uzytkownicy" gdzie "id_usera"=$ilosc


no i wszystko byloby cacy, gdyby nie to, ze jezeli 2-ch uzytkownikow zalozy konto w tej samej sekundzie to jeden wpis robi sie poprawnie, a drugi jest pusty (wpis bez zadnych danych)


Jak mozna temu zaradzic?
mortus
Kolumna id_usera powinna zwiększać się automatycznie. Ilość user-ów ma niewiele (a na pewno nie powinna mieć nic) wspólnego z ich identyfikatorami. System jest źle zaprojektowany.

EDIT
Liczbę user-ów (bez tych, którzy np. konto usuną) można pobrać zawsze:
  1. SELECT COUNT(`id_usera`) FROM `uzytkownicy`

Gwoli wyjaśnienia. Załóżmy, że w systemie masz 5 użytkowników:
id nazwa
1 user1
2 user2
3 user3
4 user4
5 user5
W takim wypadku w tabeli dane ilosc_userow jest równa 5.
Załóżmy, że użytkownik 1 usunie konto. Wtedy ilosc_userow jest równa 4. Dodanie nowego usera powoduje, że ilosc_userow znowu się zwiększa do 5, ale w bazie danych jest już użytkownik o id 5 i nie można dodać takiego użytkownika. Nic z tym nie zrobisz, po prostu system jest źle zaprojektowany.
shycat
hmm... pewnie masz racje wprowadze ta zmiane, do tej pory uzywalem zapisu ilosc w innej tabeli, poniewaz po 1. liczba uzytkownikow jest podana na dole strony i myslalem, ze uzywanie SELECT COUNT bedzie bardziej obciazalo baze niz pobranie "gotowej" wartosci a po 2. wpis w innej tabeli eliminowalby rowniez uzywanie SELECT COUNT podczas rejestracji...

Zastanawia mnie czy COUNT jest "lekkie" czy przy duzej ilosci rekodrow moze zamulic. Sam myslalem nad rozwiazaniem:

<zablokuj tymczasowo baze>
wykonaj instrukcje
<odblokuj baze>

ale nie wiem czy istnieje taka mozliwosc oraz czy jest skuteczna (co z uzytkownikiem/uzytkownikami, ktory w tym czasie jest blokowany - tj. rowniez zaklada konto)

inny sposob, aczkolwiek nie wiem czy mozliwy, to cos w rodzaju:

  1. INSERT INTO tabela (COUNT(id)++,'dane1','dane2')



Inna sprawa jest czy jezeli uzyje metody pobierania przez COUNT - czy to bez blokowania bazy wystarczy



Ps. jezeli chodzi o usuwanie uzytkownikow i o rzeczy o ktorej piszesz to mam tego swiatomosc i po prostu nie usuwam wpisow tylko mam kolumne "typ" z danymi 1|2|3 dla konto aktywne|konto nieaktywne|konto usuniete
mortus
Jedynym słusznym wyjściem jest przeprojektowanie bazy danych, co wyjaśniłem wyżej po wyedytowaniu wiadomości. Istnieje możliwość blokowania tabel, jednak dla któregoś z dwóch użytkowników zawsze skończy się to błędem. Liczbę użytkowników jak najbardziej możesz przechowywać w tabeli dane, jednak to ta liczba powinna być uzależniona od liczby wierszy w tabeli uzytkownicy, a nie na odwrót. Najlepiej będzie zmusić kolumnę id_usera do automatycznego zwiększania wartości.

Cytat
Ps. jezeli chodzi u usuwanie uzytkownikow i o rzeczy o ktorej piszesz to mam tego swiatomosc i po prostu nie usuwam wpisow tylko mam kolumne "typ" z danymi 1|2|3 dla konto aktywne|konto nieaktywne|konto usuniete

Przez lata może to doprowadzić do olbrzymiej nadmiarowości danych, co będzie owocowało brakiem optymalności. Zauważ, że do każdego zapytania musisz dodawać warunek sprawdzający, czy użytkownik przypadkiem już nie istnieje, co przy dużej liczbie rekordów będzie dodatkowo obciążać bazę danych.
shycat
Cytat
Zauważ, że do każdego zapytania musisz dodawać warunek sprawdzający, czy użytkownik przypadkiem już nie istnieje


Nie bardzo rozumiem co masz na mysli. To czy uzytkownik "istnieje" czyli wartosc kolumny "typ", jest sprawdzane tylko podczas logowania, aktywacji konta (klikniecie w link z emaila) i w momencie gdy ktos wchodzi na profil danego uzytkownika.


Ok, wiec teraz w sumie moje istotne pytanie, czy jest jakis sposob wykonania przykladu, o ktorym juz pisalem:

  1. INSERT INTO tabela (COUNT(id)++,'dane1','dane2')
(lub w inny sposob, ale za pomoca jednego zapytania)

Czy po prostu musze pierw pobrac wartosc COUNT, a potem count+1 i uzyc tego jako ID
dmateo
Nie można tego zrobić transakcją?
luck
Triggery założone na INSERT i DELETE rozwiążą wszystkie problemy.
shycat
Hm, wlasnie skonczylem wertowanie tego forum i czesci wynikow google dla roznych stron... i nigdzie nie znalazlem informacji o tym, jak mozna zablokowac na chwile baze danych, po to, aby dwa wpisy sie nie zdublowaly (nie zaleznie czy ID jest pobierane z innej tabeli czy przez COUNT biezacej) i oczywiscie po wykonaniu zadania baze odblokowac... oraz zeby w czacie "blokowania" inny uzytkownik, ktory akurat w tej samej sekundzie wykona INSERT'a mogl w jakis sposob dodac swoj wpis... takze poddaje sie w moich poszukiwaniach i prosze o w miare dokladna instrukcje, bo "tiggery zalozone na insert i delete"... nic mi nie mowi, wspomniane transakcje tez chyba nie pomoga, poniewaz z tego co wyczytalem, to uzywa sie ich glownie na dzialaniach pomiedzy roznymi tabelami - a nie tu tkwi moj problem.

-------------------------------------------------------------------------

Pobuszowałem jeszcze troche i mysle, ze w moim przypadku dobre bedzie uzycie AUTO_INCREMENT dla `id` userow + LOCK I UNLOCK TABLES. Nigdzie nie znalazlem informacji o tym, ze

Cytat
Istnieje możliwość blokowania tabel, jednak dla któregoś z dwóch użytkowników zawsze skończy się to błędem


lecz z tego co wyczytalem, "drugi" uzytkownik bedzie musial "poczekac", az "pierwszy" skonczy wykonywac zapytanie.
luck
Cytat(shycat @ 7.09.2011, 23:40:01 ) *
"tiggery zalozone na insert i delete"... nic mi nie mowi

Zerknij sobie np. tutaj: http://forge.mysql.com/wiki/Triggers. Trzeba chwilę poświęcić na czytanie, ale zapewniam Cię, że warto.
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.