Autor Zpráva
varch
Profil *
Ahoj, našel jsem že zamknout tabulky v transakci můžu příkazem
SELECT ... FOR UPDATE
ale neni mi jasný jestli můžu napsat například:
SELECT produkty FOR UPDATE
nebo je to omezené jen na něco
SELECT produkty FOR UPDATE WHERE ID = ?

v tom prvním případě se zamykají každé položky zvlášť nebo se zamkne celá tabulka? Byl by to problém kdybych tam měl třebas 5 tisíc produkt a ty by se zamykaly postupně.

Dál sem našel LOCK TABLES, a na mysql stránce je napsáno tohle "LOCK TABLES is not transaction-safe and implicitly commits any active transaction before attempting to lock the tables."
Jestli jsem to správně přeložil tak je tam napsáno že zamknutí tabulky se provede teprve potom až se provedou všechny předešlé operace. Nechápu v čem to neni bezpečné. Je přeci jasný že se nejdříve musí provést předešlé operace a pak se to teprve může zaknout. Bylo by asi blbý kdyby se uprostřed jedné operace najednou zamkla tabulka. V čem to neni teda bezpečné?
ttttttt
Profil *
varch:
ale neni mi jasný jestli můžu napsat například:
SELECT produkty FOR UPDATE
Můžeš, viz syntaxe SELECTU. Naopak, ten druhý příklad se zapisuje v jiném pořadí.


v tom prvním případě se zamykají každé položky zvlášť nebo se zamkne celá tabulka? Byl by to problém kdybych tam měl třebas 5 tisíc produkt a ty by se zamykaly postupně.

If you use FOR UPDATE with a storage engine that uses page or row locks, rows examined by the query are write-locked until the end of the current transaction.
Pokud čteš celou tabulku, zamkne se celá tabulka. Jestli je zamčená tabulka problém záleží na tom, co je pro tebe problém, jak máš nastavenou izolaci transakcí, zatížení databáze, …

Dál sem našel LOCK TABLES, a na mysql stránce je napsáno tohle "LOCK TABLES is not transaction-safe and implicitly commits any active transaction before attempting to lock the tables."
Jestli jsem to správně přeložil tak je tam napsáno že zamknutí tabulky se provede teprve potom až se provedou všechny předešlé operace. Nechápu v čem to neni bezpečné.
Není to not-safe, ale not transaction-safe, tedy to nedokáže spolupracovat s transakcemi, a je potřeba všechny transakce nejdřív ukončit. Transakce se dělají proto, aby databáze dokázala vykonávat víc příkazů naráz, a pro uživatele to vypadalo stejně (podobně), jako kdyby běžela jen jedna transakce. LOCK TABLES to celé zruší a umožní práci jen v jedné session.

LOCK TABLES je jiný mechanismus, který vynutí konzistenci tak, že zakáže vykonávání příkazů naráz, takový přístup hrubou silou. Kdyby spolupracoval s transakcemi, mohlo by jít třeba zamknout tabulku pro čtení a číst ji i v transakcích, ale nejde to.
varch
Profil *
ttttttt:
Naopak, ten druhý příklad se zapisuje v jiném pořadí.
:-(, jo máš pravdu, já ten první zkopíroval a pak sem to dopsal aniž bych si uvědomil že to má být opačně.

Transakce se dělají proto, aby databáze dokázala vykonávat víc příkazů naráz, a pro uživatele to vypadalo stejně (podobně), jako kdyby běžela jen jedna transakce. LOCK TABLES to celé zruší a umožní práci jen v jedné session.
na serveru mám nastaveno že se smí provádět max. 5 skriptů současně, takže když v jendom skriptu poběží transakce a v druhém dám LOKC TABLES, tak se ta transakce v prvním skriptu zruší? Nebo ten druhý skript bude čekat až skončí transakce v prvním skriptu? Moc sem to nepochopil :-)


opravdu to jde? já v té syntaxi selectu nikde nevidím že by tam byl možný výběr tabulky, vždy tam je SELECT * (nebo konkrétní položka) FROM produkty FOR UPDATE
Když napíšu tohle do phpMyAdmin SQL dotazu:
START TRANSACTION
SELECT chat FOR UPDATE
COMMIT
tak mi to napíše :
Statická analýza:
Při analýze bylo nalezeno 1 chyb.
Nerozpoznané klíčové slovo. (near "FOR UPDATE" at position 31)
SQL dotaz: Dokumentace
START TRANSACTION SELECT chat FOR UPDATE COMMIT
MySQL hlásí: Dokumentace
#1064 - Vaše syntaxe je nějaká divná blízko 'SELECT chat FOR UPDATE
COMMIT' na řádku 2



zapoměl jsem tam ;...
START TRANSACTION;
SELECT chat FOR UPDATE; // tady tedy uzamykám celou tabulku
SELECT * FROM chat; // a tady vybírám všechny data
COMMIT;
napíše mi to:
Chyba
SQL dotaz: Dokumentace
SELECT chat FOR UPDATE
MySQL hlásí: Dokumentace
#1054 - Neznámý sloupec 'chat' v field list


Používám PDO, chtěl jsem to jen namátkou zkusit.


$db->beginTransaction();
    $db->query('SELECT * FROM chat FOR UPDATE');
    sleep(15);
    $db->commit();
během sleep sem se pokusil vložit do tabulky nový záznam a přesně jak jsem chtěl druhý skript musel čekat, ale když tam budu mít milion záznamů nebude to zamykání představovat problém? Zamkne se teda celá tabulka a ne postpně všechny záznamy?
tttttt
Profil *
varch:
na serveru mám nastaveno že se smí provádět max. 5 skriptů současně, takže když v jendom skriptu poběží transakce a v druhém dám LOKC TABLES, tak se ta transakce v prvním skriptu zruší? Nebo ten druhý skript bude čekat až skončí transakce v prvním skriptu? Moc sem to nepochopil :-)
Nevím, tipuju, že LOCK TABLES bude čekat na dokončení transakcí. Ale není to moc důležité, používej buď MyISAM a LOCK TABLES, nebo InnoDB a transakce, ne obojí.

opravdu to jde? já v té syntaxi selectu nikde nevidím že by tam byl možný výběr tabulky, vždy tam je SELECT * (nebo konkrétní položka) FROM produkty FOR UPDATE
Syntaxe je stejná jako u SELECT, jen se na konci připíše FOR UPDATE. Databáze pak zamkne to, co bylo použité v dotazu, podle toho, jak umí (řádky, stránky, tabulky). Není potřeba mít dotaz na zamykání a pak dotaz na výběr (a pokud by v transakci nebyly jiné dotazy, nejsou transakce ani potřeba, ale předpokládám, že to jsou jen ilustrační přiklady).

varch:
během sleep sem se pokusil vložit do tabulky nový záznam a přesně jak jsem chtěl druhý skript musel čekat, ale když tam budu mít milion záznamů nebude to zamykání představovat problém? Zamkne se teda celá tabulka a ne postpně všechny záznamy?
Zamykání miliónu záznamů bude určitě rychlejší než čtení miliónu záznamů. Zamykání je jen abstrakce, databáze uvnitř může dělat různé věci, třeba držet různé historie pro různé transakce, zamykat podle toho, jak dotaz vypadá. Co konkrétně dělá MySQL nevím.
varch
Profil *
$db->query('SELECT * FROM chat FOR UPDATE');
timhle příkazem vybírám všechno a zároven vytvářím zámky, ale já potřebuju aby do té tabulky nikdo nemohl nic zapisovat po dobu co bude probíhat transakce. Jak to mám teda udělat?
tttttt
Profil *
varch:
potřebuju aby do té tabulky nikdo nemohl nic zapisovat po dobu co bude probíhat transakce.
Hádám, že ve skutečnosti potřebuješ něco jiného (třeba číst uvnitř transakce jen ta samá data, do kterých nikdo nezapsal). Pokud bys potřeboval všem ostatním zabránit v přístupu při probíhající transakci, pak nezbývá než používat LOCK TABLES. Ale nepoužívá se to, skoro nikdo nechce databázi, ke které může přistupovat jen jeden uživatel.
varch
Profil *
tttttt:
ve skutečnosti to potřebuju na tohle. Budu mazat rubriku a mám i tabulku kde je ID rubriky a ID článku, potom co vymažu všechny data z řadící tabulky by mohl někdo zapsat id rubriky kterou chci smazat a existující id článku. Nastavil jsem tam cizí klíč a už nemusím uzamykat celou tabulku ale jen konkrétní rubriku a zápis do řadící tabulky bude čekat. Je toho víc, snad se mi to podaří.
tttttt
Profil *
Nastav při vytvoření cizího klíče ON DELETE CASCADE a při smazání rubriky se smažou i články, které na ni odkazují.
varch
Profil *
tttttt:
Nastav při vytvoření cizího klíče ON DELETE CASCADE a při smazání rubriky se smažou i články, které na ni odkazují.
to mi přijde trochu drastický. Při smazání rubriky se články přesunou do nezařazených.
tttttt
Profil *
Tak ON DELETE SET NULL?
varch
Profil *
tttttt:
ON DELETE SET NULL?
a to jde změnit na null?
co by am teda byla v té řadící tabulce? ID článku = NULL a ID rubriky = NULL?
Keeehi
Profil
varch:
Jestli máš mezi rubrikami a články vazbu M:N tak platí [#8] od tttttt. ON DELETE CASCADE bude samozřejmě jen na vazbu a nebude se propagovat až ke článku.

Druhá možnost je se na uzamykání vykašlat a upravit PHP kód tak, aby se vyrovnal i s neexistujícími rubrikami. Což by nemělo být nic extra těžkého, konkrétní implementace záleží však vždy na způsobu, jakým to máš navržené.

Na tohle úplně nejsem odborník, ale myslím, že pokud budeš mít izolaci transakcí alespoň na úrovni repeatable read a tak bys s paralelním mazáním snad neměl mít problém.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0