Hlavní navigace

PHP okénko: Využití unikátních klíčů v databázi

Jakub Vrána 25. 3. 2005

Začíná PHP okénko, které vám bude přinášet drobné postřehy z programování v PHP, vždy pokud možno s uvedením konkrétních ukázek kódu. První okénko ukazuje, jak lze s využitím unikátních indexů elegantně a korektně ukládat do databáze uživatelská jména.

Pokud má webová aplikace možnost registrace uživatelů, obvykle jim dovoluje zvolit uživatelské jméno, pod kterým se k aplikaci budou přihlašovat. Obvykle také chceme, aby toto uživatelské jméno bylo jednoznačné (obzvláště pokud jim na jeho základě vytvoříme e-mailovou adresu nebo URL). Dá se to jako obvykle řešit několika způsoby.

<?php
// špatný kód
if (mysql_result(mysql_query("SELECT COUNT(*) FROM uzivatele WHERE login = '$_GET[login]'"), 0)) {
    echo "Uživatel již existuje.\n";
} else {
    mysql_query("INSERT INTO uzivatele (login) VALUES ('$_GET[login]')");
}

// opravený kód
mysql_query("LOCK TABLES uzivatele WRITE");
if (mysql_result(mysql_query("SELECT COUNT(*) FROM uzivatele WHERE login = '$_GET[login]'"), 0)) {
    echo "Uživatel již existuje.\n";
} else {
    mysql_query("INSERT INTO uzivatele (login) VALUES ('$_GET[login]')");
}
mysql_query("UNLOCK TABLES");

// elegantní kód, předpokládá existenci unikátního klíče nad sloupcem login
mysql_query("INSERT INTO uzivatele (login) VALUES ('$_GET[login]')");
if (mysql_errno() == 1062) {
    echo "Uživatel již existuje.\n";
}
?> 

Proč je první kód špatně? Důvod je ten, že k webové aplikaci může přistupovat více uživatelů zároveň, tím pádem mezi provedením SELECT a INSERT může tyto dvě operace provést někdo jiný, a uživatel se tak vloží dvakrát. Je to sice spíše teoretická možnost, ale je lepší si ušetřit bezesné noci hledáním takovýchto problémů. Ve většině databází se tento problém řeší transakcemi, MySQL je však umožňuje pouze za určitých okolností a jako náhradu nabízí zamykání tabulek.

To používá druhý příklad, který je už po formální stránce správně, je ale poněkud krkolomný a skrývá riziko neodemčení tabulky (pokud by uživatel přerušil provádění skriptu před odemčením tabulky a pokud se používá persistentní připojení k databázi, tak už si z tabulky uzivatele nikdo nic nepřečte). Toto riziko se dá řešit doplněním kódu register_shutdown_function(create_function('', 'mysql_query("UNLOCK TABLES");')); před zamknutím tabulky, to se už ale krkolomnost dostává na kritickou hranici.

Třetí způsob je naproti tomu elegantní. Předpokládá pouze existenci unikátního indexu nad sloupcem login, ten by ale měl existovat tak jako tak, protože výrazně urychluje dotazy do tabulky omezené tímto sloupcem. MySQL chyba č. 1062 nastane v případě duplicity unikátního klíče.


Podobně laděné texty můžete najít i na autorově weblogu PHP triky.

Našli jste v článku chybu?

25. 3. 2005 13:37

V příspěvku je několik faktických chyb:

"zamykani tabulek je blbost, co kdyz se budou registrovat 2 uzivatele?"
Zamykání tabulek funguje tak, že když je tabulka zamknutá a proces udělá "LOCK TABLES", tak čeká na odemknutí procesem, který ji zamkl. Zkuste si o tom nejprve něco nastudovat, než napíšete, že to je blbost.

"opravdu se jedna jen o teoretickou moznost, ktera nenastane a resit to nejakym selectem..."
To, že se někdo pokusí zaregistrovat pod již obsazeným …





28. 3. 2005 20:23

Docela se zájemem jsem si přečetl diskuzi pod tímto článkem. A mám z ní velmi smíšené pocity.

Totiž, článek není určen začátečníkům ani rádoby-programátorům. Možná proto přehlíží takové zásadní věci, jako je "slashování" proměnných - autor to nejspíš považuje za samozřejmé a nechce odvádět pozornost od tématu. A tématem je atomicita operací. Povídání o nějaké "registraci uživatelů", to je jen omáčka, aby výklad získal praktičtější ráz.

A hle. Pod článek se vyro…

DigiZone.cz: Další dva kanály nabídnou HbbTV

Další dva kanály nabídnou HbbTV

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Vitalia.cz: Jak koupit Mikuláše a nenaletět

Jak koupit Mikuláše a nenaletět

Podnikatel.cz: Platební brány a EET? Stále s otazníkem

Platební brány a EET? Stále s otazníkem

Podnikatel.cz: Prodává přes internet. Kdy platí zdravotko?

Prodává přes internet. Kdy platí zdravotko?

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Vitalia.cz: 9 největších mýtů o mase

9 největších mýtů o mase

Podnikatel.cz: 1. den EET? Problémy s pokladnami

1. den EET? Problémy s pokladnami

DigiZone.cz: Flix TV má set-top box s HEVC

Flix TV má set-top box s HEVC

Měšec.cz: Finančním poradcům hrozí vracení provizí

Finančním poradcům hrozí vracení provizí

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

Vitalia.cz: Tesco: Chudá rodina si koupí levné polské kuře

Tesco: Chudá rodina si koupí levné polské kuře

Podnikatel.cz: EET zvládneme, budou horší zákony

EET zvládneme, budou horší zákony

Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

DigiZone.cz: NG natáčí v Praze seriál o Einsteinovi

NG natáčí v Praze seriál o Einsteinovi

Lupa.cz: Avast po spojení s AVG propustí 700 lidí

Avast po spojení s AVG propustí 700 lidí

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...