none
Zamezení přístupu ostatním uživatelům k přečteným řádkům v transakci

    Dotaz

  • Dobrý den,

    mám jeden problém s viceuživatelským přístupem do databáze a nejsem si úplně jist vhodným řešením (jedná se o webovou aplikaci). Zkusím popsat nějaký učebnicový příklad. V systému existuje funkcionalita, která hromadně mění atribut A u sady záznamů jedné tabulky. Předtím, než se může změna spustit je potřeba zkontrolovat "aplikační  integritu". Např. můžu změnit atribut A z 1 na 2 pouze pokud je aktuální hodnota 1 apod. Změna do určitého stavu muže proběhnout pouze jednou a jedním uživatelem. Celá operace j v transakci s defaultním izolačním levelem.

    Teď konečně k věci :). Podle mého názoru, pokud dva (a třeba i více) uživatelů spustí tuto proceduru shodně a nad stejnými záznamy, pak si všichni můžou přečíst stejná data a myslet si, že můžou atribut změnit. Ve všech transakčních levelech si totiž uživatelé přečtou stejná data, pokud to stihnout do doby, než se jedna z nich pustí do aktualizací (neplatí samozřejmě pro READ UNCOMMITED). A po dokončení aktualizací uživatelem 1 je ke slovu puštěn uživatel 2 a ten přepíše změny uživatele 1.

    Jako řešení mě napadlo nějaká forma zámku na přečtené řádky. Uživatel 1 by přečetl x řádků a ty by se zablokovali i pro čtení po čas běhu jeho transakce. Je to hodně restriktivní :-/ ale ve výsledku by o něco málo později spuštěná transakce přečetla všechny řádky už ve změněné podobě. Uživatel 2 by dostal info, že tuto operaci už není možné s danými daty provést, protože jím přečtená data by už obsahovala předchozí úpravy. Mám v tomto tématu trochu zmatek :-/.

    Předem díky za jakoukoli odpověď.

    středa 22. prosince 2010 10:56

Odpovědi

  • Dobrý den,

    jako rozumné řešení Vašeho problému se mi jeví použití aplikačních zámků - v podstatě synchronizačního objektu na úrovni SQL Serveru. Podívejte se do Books OnLine na proceduru sp_getapplock. Před selectem by se vytvořil aplikační zámek. Jeho existence by znamenala, že jiná transakce tuto operaci již provádí.

    Další možností, jak to řešit, j použití snapshot izolační úrovně transakcí. Při ní by pokus druhé transakce updatovat záznamy již změněné a potvrzené první transakcí vyvolal update konflikt a operace by tak skončila chybou.

    S pozdravem

    Miloslav Peterka

    pondělí 10. ledna 2011 7:36

Všechny reakce

  • I u SQL existuje cosi jako výhradní zámek. Zamknou lze tabulku, stránku nebo jen řádek:

    BEGIN TRAN
    SELECT * FROM table WITH (ROWLOCK, XLOCK, HOLDLOCK) WHERE attribA = 1
    -- a nyní nemohou ostatní instance uzamčené řádky ani číst a čekají
    UPDATE table SET attribA = attirbA + 1 WHERE attribA = 1
    COMMIT

    ale v případě, že se po uzamčení čeká na nějakou akci uživatele, je to spíš cesta do pekel... Navíc i ROWLOCK obvykle zamkne i "něco okolo" a na problémy je zaděláno.

    Řešení spíš vidím v důsledném uplatňování testovacích podmínek při vlastním zápisu - tj. uživatel sice viděl, že má update povolen, ale protože byl někdo jiný rychlejší, k vlastnímu updatu již (správně) nedošlo, protože se data změnila.

     

    čtvrtek 23. prosince 2010 20:25
  • Díky za odpověď.
    pátek 24. prosince 2010 8:31
  • Dobrý den,

    jako rozumné řešení Vašeho problému se mi jeví použití aplikačních zámků - v podstatě synchronizačního objektu na úrovni SQL Serveru. Podívejte se do Books OnLine na proceduru sp_getapplock. Před selectem by se vytvořil aplikační zámek. Jeho existence by znamenala, že jiná transakce tuto operaci již provádí.

    Další možností, jak to řešit, j použití snapshot izolační úrovně transakcí. Při ní by pokus druhé transakce updatovat záznamy již změněné a potvrzené první transakcí vyvolal update konflikt a operace by tak skončila chybou.

    S pozdravem

    Miloslav Peterka

    pondělí 10. ledna 2011 7:36
  • Dobrý den,

    máte pravdu v tom, že si stejná data může přečíst více transakcí (uživatelů), ale zároveň si je všechny označí zámky jako přečtené. Žádná transakce je tedy nemůže změnit, protože by porušila zámek jiné transakce a to v Read commited (defaultní izolace) nelze. Dojde k tzv. uvýznutí a SQL Server začne ty transakce stornovat. Vámi popisované přepsání druhou transakcí výsledku z první podle původních dat dojít nemůže.

    http://msdn.microsoft.com/en-us/library/ms178104(v=sql.105).aspx


    Petr Barták
    .Net developer
    www.uzuzu.cz

    čtvrtek 21. června 2012 22:37