Autor | Zpráva | ||
---|---|---|---|
MagicPowa Profil |
#1 · Zasláno: 31. 1. 2010, 21:48:36
Zdravím, bude to trochu obecný ale snad na to existuje řešení a někdo bude schopnej mě nasměrovat jak dále.
Mám tabulku s pár záznamy, momentálně do 10ti záznamů. Vypíšu je do řádků pod sebe a udělal jsem si skript, díky kterému je můžu posouvat. Nahoru a dolů jsou odkazy díky nimž to krokově řadím. 1 klik - posun o 1. 1 | Položka 1 | Nahoru | Dolů 2 | Položka 2 | Nahoru | Dolů 3 | Položka 3 | Nahoru | Dolů atd. Stává se mi toto: pokud klikám POMALU, klik => proběhne GET => mám tam SELECT => UPDATE => dobrý pokud klikám RYCHLE, klik klik klik... => proběhne GET => SELECT a ještě než se to UPDATNE tak proběhne rovnou další SELECT a ten vybere špatnou hodnotu, kvůli tomu, že ještě neproběhnul ten UPDATE Nejdříve jsem si myslel, že to není možné jak může nějakej dotaz předběhnout následující, když ještě nedoběhnul ale po opakovaném zkoušení se mi potvrdilo to co píšu. Localhost a DB mám na vlastním počítači, je možné, že na webovém serveru u hostingu by to nedělalo, protože ten je rychlejší a SQL dotazy se vykonávaj rychleji ale na to se nechci spoléhat. Setkal se s tím někdo? Jak to řešit? Děkuji za každou pomoc, v případě, že by bylo nutné ukázat zdrojový kód ukážu ho ale momentálně si myslím, že to není nutné je to jen pár řádků základních věcí. |
||
Alphard Profil |
#2 · Zasláno: 31. 1. 2010, 21:59:12
Průběh serverového scriptu by měl být zlomek sekundy, zdržení bych tipoval spíš někde na cestě, což se v ostrém provozu zřejmě ještě zhorší.
Jde spíš o mechanismus posunu, používáte AJAX nebo se obnovuje celá stránka? Neměl byste umožnit další akci, dokud neproběhla ta předchozí. Pro zrychlení je možné využít javascript, velice rychle posunovat pouze na stránce (třeba i Drag&drop) a na závěr tlačítko Uložit, které odešle nové pořadí na server. |
||
imploder Profil |
#3 · Zasláno: 31. 1. 2010, 21:59:54
|
||
MagicPowa Profil |
#4 · Zasláno: 31. 1. 2010, 22:48:39
Alphard:
AJAX nepoužívám, a ani nehodlám. To moje je jen klasické $_GET v PHP s 1x SELECTEM a 2x UPDATEM. Pro zrychlení se mi JS, jQuery používat nechce, jednak protože to neovládám a jelikož mi to přijde jako záplata nedokonalosti jiné věci. imploder: Článek jsem přečetl i další navazující, který jsem neúspěšně, protože je přímo na dotaz v DB a ne pomocí PHP. Googlil jsem tedy transakce v mysql_query a využil: mysql_query("START TRANSACTION;"); mysql_query("SELECT..."); mysql_query("UPDATE..."); mysql_query("UPDATE..."); mysql_query("COMMIT;"); Zápis prošel, dokonce to nehlásilo ani chybu ale co se týče funkčnosti, tak problém přetrvává. Je možné, že to nemám zapsáno správně. Nápady? |
||
Alphard Profil |
#5 · Zasláno: 31. 1. 2010, 22:59:47
Nemyslel jsem to jako záplatu, ale jako pohodlnější možnost.
„To moje je jen klasické $_GET v PHP s 1x SELECTEM a 2x UPDATEM.“ Tohle mi připadá jako nedostatečný popis. Jestli se odešle chybný požadavek, nezachrání to ani transakce, proto jsem ji ani neodkazoval. Jak váš systém funguje? 1. stránka s odkazem 2. klik na odkaz 3. odeslání požadavku a současný reload stránky 4. stránka je znovu načtená, jsou na ní vygenerované nové odkazy 5. pokračuje krok 2 Takhle by mělo vše fungovat. Kde je u vás chyba? Ideální by byla živá ukázka. |
||
MagicPowa Profil |
#6 · Zasláno: 1. 2. 2010, 17:12:26
Takže jsem udělal ukázku a dal na web. Je to rychlejší než u mě, jak jsem předpokládal, takže musíte klikat rychleji. K nalezení je tady.
Před tím, než to vyzkoušíte, tak si to zresetujte tlačítkem aby jste měli indexy řazení 1 2 3 4. Jakmile budete mít např. 1 3 3 4 už je to špatně, zresetujte a vyzkoušejte znova. |
||
TomášK Profil |
#7 · Zasláno: 1. 2. 2010, 21:30:27 · Upravil/a: TomášK
Alphard:
Javascript by to z hlediska praktického pravděpodobně vyřešil, ale "čisté" řešení by nemělo spoléhat na to, že mezi požadavky bude nějaká prodleva nebo že uživatel pošle dvakrát tentýž požadavek. Myslím, že by databáze měla být taková, aby k podobné situaci nedošlo, ať se děje co se děje. Zdá se mi, že transakce zachrání i špatný požadavek - aspoň ve smyslu, že databáze bude v konzistetním stavu (i když možná ne tom, který uživatel chtěl). Není to výhra, ale lepší než současný stav. MagicPowa Tipuju, že k chybě možná dojde, pokud se odešle dvakrát tentýž požadavek, tj. uživatel klikne ještě než se nová stránka začne načítat. To bych se pokusil detekovat a případné další odeslání ignorovat. A dále bych ošetřil skript tak, aby databáze zůstala vždy v konzistetním stavu. Pokud chtete využít transakce, zkontroloval bych, jestli není nastavený autocommit, případně jestli jsou tabulky v InnoDB, jinak myslím nefungují. Případně se mi zdá, že by dotazy šly zredukovat zredukovat na jeden UPDATE: - předpokládám,že v proměnné chci prohodit záznamy na pozicích $pos a $pos+1: UPDATE item SET position=position+IF(position=$pos, 1, -1) WHERE position IN ($pos, $pos+1) Edit: Opraveno dle upozornění Kajmana, dík |
||
Kajman_ Profil * |
#8 · Zasláno: 2. 2. 2010, 08:31:40
position+=IF(position=$pos, 1, -1) bude asi nutné rozepsat jako
position=position+IF(position=$pos, 1, -1) |
||
josh Profil * |
#9 · Zasláno: 2. 2. 2010, 11:31:22
Kajman:
„position=position+IF(position=$pos, 1, -1)“ můžu se zeptat ohledně tohoto zápisu? Tento UPDATE (společně se zbytkem Tomášova kódu) prohodí pozici dvou řádků? Já to vždy dělal dvěma dotazy, ale pokud jsem to dobře pochopil, tohle by bylo asi lepší. Nebo se pletu? |
||
TomášK Profil |
#10 · Zasláno: 2. 2. 2010, 12:10:09 · Upravil/a: TomášK
josh:
Ano, mám za to, že uvedený kód prohodí dva řádky. K řádku se stejnou pozicí jako je v proměnné $pos přičte 1, od ostatních odečte 1. WHERE zajistí, že pracuju jen se záznamem na pozici $pos a následujícím. Výhodou jednoho dotazu je, že proběhne atomicky, tj. nemusím přemýšlet o tom, co se stane, když běží současně dva skripty a dotazy se provádí "na střídačku". Stejnou funkčnost poskytnou dva dotazy a trasnakce, kód bude pravděpodobně čitelnější. Případně pokud jsou ty dva dotazy udělané tak, že jim nevadí, když budou proložené jinými dotazy, je to v pořádku. Je ale potřeba vědět, že s tím může být problém a nějak ho řešit, případně i pštrosím algoritmem. |
||
MagicPowa Profil |
#11 · Zasláno: 2. 2. 2010, 13:41:08 · Upravil/a: MagicPowa
Tak jsem to zkusil pomocí UPDATU s IF a WHERE IN, zkrátka skript od TomášK a funguje to perfektně. Eliminuje to přesně ten problém co jsem potřeboval!
Ještě tam vznikal problém přitom, když jsem vymazal některý záznam, takže řazení bylo 1, 2, 3, -, 6, 7 ale to jsem vyřešil dosazením rozdílu za jedničku +(1). Jinak ten UPDATE s IF a WHERE IN tam mám dvakrát pro řazení nahoru a dolů, protože u jednoho odečítám a u druhého přičítám. Pokud by někdo chtěl postnout ten skript, tak ho sem vložím. Díky všem, kteří mi pomohli tohle vyřešit! //na předchozím odkaze jsem to neupravoval, je tam pořád staré řešení |
||
MagicPowa Profil |
#12 · Zasláno: 2. 2. 2010, 13:54:23
Ještě jsem zkoušel staré řešení s vypnutým i zapnutým autocommitem, tabulky na InnoDB a dělalo to stejně problém s duplikací indexů řazení.
|
||
josh Profil * |
#13 · Zasláno: 2. 2. 2010, 14:22:33
MagicPowa:
„Pokud by někdo chtěl postnout ten skript, tak ho sem vložím.“ mohl bys, prosím? Nejsem si jistý, jak to udělat druhým směrem, ty plus a mínus jedničky mě tam matou :-) Děkuji. |
||
MagicPowa Profil |
#14 · Zasláno: 2. 2. 2010, 15:13:14
$presun = GET - id_kategorie
$umisteni = GET - nahoru, dolu $razeni = GET - razeni public static function posouvani_nahoru_dolu($tabulka, $sloupec_id, $sloupec_razeni, $presun, $umisteni, $razeni) { if(isset($presun)) { if($umisteni=="nahoru") { $radit_podle = "DESC"; $znamenko = "<"; } elseif($umisteni=="dolu") { $radit_podle = "ASC"; $znamenko = ">"; } $vyber_presun = mysql_query("SELECT ".$sloupec_id.", ".$sloupec_razeni." FROM ".$tabulka." WHERE ".$sloupec_razeni." ".$znamenko." '".$razeni."' ORDER by $sloupec_razeni $radit_podle") or die (mysql_error()); $data_presun = mysql_fetch_array($vyber_presun); $radit = $data_presun['razeni']; if($data_presun['razeni']!=NULL && $umisteni=="nahoru") { $rozdil = $razeni - $data_presun['razeni']; mysql_query("UPDATE ".tabulka." SET $sloupec_razeni=$sloupec_razeni+IF($sloupec_razeni=$radit, $rozdil, -1) WHERE $sloupec_razeni IN ($radit, $radit+$rozdil)") or die(mysql_error()); } elseif($data_presun['razeni']!=NULL && $umisteni=="dolu") { $rozdil = ($razeni - $data_presun['razeni'])*-1; mysql_query("UPDATE ".tabulka." SET $sloupec_razeni=$sloupec_razeni+IF($sloupec_razeni=$radit, -$rozdil, 1) WHERE $sloupec_razeni IN ($radit, $radit-$rozdil)") or die(mysql_error()); } } } String::posouvani_nahoru_dolu(tabulka, id_sloupec, "razeni", $_GET['presun'], $_GET['umisteni'], $_GET['razeni']); |
||
Časová prodleva: 14 let
|
0