Autor Zpráva
lionel messi
Profil
Zdravím,

pracujem na vlastnom redakčnom systéme a narazil som na nutnosť riešiť atomicitu na úrovni MySQL.

Pri tvorbe článku vždy zálohujem v DB aj jeho koncept, čiže každú minútu posielam pomocou AJAXu dotaz na zápis, resp. aktualizáciu údajov v databáze. Po kliknutí na tlačidlo odoslať sa vykoná zodpovedajúca operácia, ktorá publikuje článok (= ak z neho neexistuje koncept, vloží sa nový záznam, ak existuje, nastaví sa stĺpec, ktorý rieši, či je skrytý, alebo publikovaný, zodpovedajúcim spôsobom).

Narazil som však na problém s atomicitou – stane sa, že po kliknutí na odoslanie počas spracovania operácie prebehne súčasne aj uloženie konceptu - buď sa uložia dva totožné články (jeden publikovaný a jeden koncept), alebo sa v článku nežiaducim spôsobom zmení nastavenie zverejnenia (skryje sa).

Rád by som podobnému správaniu predišiel, a tak mi napadlo vytvoriť transakciu pre dotaz zameraný na ukladanie konceptov. Chcel by som sa spýtať, či ide o dobré riešenie. Nižšie uvádzam dotaz:

START TRANSACTION;

-- vyberieme najnovší záznam, porovnáme dátum, napíšeme dotaz pre vkladanie
SELECT TIMEDIFF(now(), datum) as rozdiel FROM tabulka ORDER BY id DESC LIMIT 1;
INSERT INTO tabulka (stlpec1, stlpec2) VALUES (hodnota1, hodnota);

-- ak je rozdiel menej než 5 sekúnd, zrušíme transakciu
IF rozdiel < '0:00:05' THEN
ROLLBACK;

-- ak nie, vkladáme dáta
ELSE
COMMIT;
END IF;

Na záver by ma ešte zaujímalo, prečo mi PHPMyAdmin podčiarkuje slovo IF ako syntaktickú chybu a tvrdí, že na konci dotazu sa „očakávala ukončovacia úvodzovka“. Podľa tutoriálov na webe ani knihy o SQL totiž syntaktickú chybu nikde nevidím.

Vopred veľmi pekne ďakujem za každú radu.
Keeehi
Profil
lionel messi:
Mno, a proč to nevyřešíš už na straně javascriptu? Jakmile klikneš na tlačítko odeslat, tak zrušíš ten timeout co spouští AJAX. A pokud zrovna běží AJAXový požadavek, tak odeslání pozdržíš do té doby, než ten AJAX nedoběhne. Nepřijde mi to nijak složité. Viděl bych to asi takto:

var isAjaxRunning = false;
var shouldSubmit = false;

var ajaxTimer = setInterval(function() {
    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        isAjaxRunning = false;
        
        if(shouldSubmit) {
            form.submit();
            clearInterval(ajaxTimer);
        }
    };

    xhr.open('GET', 'https://example.org');
    xhr.send();
    isAjaxRunning = true;
}, 60 * 1000);

form.onsubmit = function() {
    if(isAjaxRunning) {
        shouldSubmit = true;
    
        event.preventDefault();
        return;
    }
    
    clearInterval(ajaxTimer);
    return;
}

Bude to chtít upravit ale obecnou představu, jak by to asi mělo fungovat z toho dostaneš. Jinak z pohledu UX by to chtělo, pokud ten formulář bude čekat na dokončení AJAX požadavku, aby se tlačítko pro odeslání zneaktivnilo a objevil se tam nějaký spinner, aby bylo jasné, že se to odesílá.
lionel messi
Profil
Keeehi:
Nepřijde mi to nijak složité. Viděl bych to asi takto:

Ďakujem. Áno, to bude asi najčistejšie riešenie, ešte sa s tým JS trochu pohrám.

Napriek tomu by ma zaujímala aj tá údajná syntaktická chyba v [#1], pretože transakcie budem zrejme beztak potrebovať. :-)
Kajman
Profil
lionel messi:
tá údajná syntaktická chyba
Je možné, že to je jen chyba v PHPMyAdmin a tamním vlastním parseru.

Ale než kontrolovat čas od posledního uložení, spíše bych s konceptem posílal identifikaci verzi článku, kdy byl ručně uložen a koncept je jeho úprava. Pokud přijde koncept ke starší verzi článku (tedy byla dříve ručně potvrzená rozpracovaná verze tlačítkem), můžete ho např. ignorovat.
ttttt
Profil *
lionel messi:
Napriek tomu by ma zaujímala aj tá údajná syntaktická chyba v [#1], pretože transakcie budem zrejme beztak potrebovať. :-)

PHPMyAdmin nejspíš příkazy vykonává jako dotazy. IF je konstrukce, kterou lze použít jen v uložené proceduře, triggeru nebo události (event), není to dotaz (query).


Ten SQL kód má několik problémů

* rozdiel je potřeba uložit do proměnné pomocí SELECT INTO
* INSERT by mohl být až v ELSE větvi, po vyhodnocení podmínky
* jestli MySQL umí unikátní funkční index, dá se to celé vyřešit tím, že se nadefinuje, že unikátní index na časem zaokrouhleným na 5 vteřin

A raději řešení, co navrhoval Kajman.

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