Transakcje

pyt Q

Witam, Użytkownik "Sławomir Szyszło" napisał w wiadomości Dnia Mon, 6 Jul +, "Adam K." wklepał(-a):
Chyba jednak nie, gdy rozpoczne transakcje w trybie read commited, wykonam insert do bazy (nie wiem czy to ma znaczenie, ale dodawanie przy pomocy procedury skladowanej), to póki nie zrobie COMMIT/ROLLBACK inny proces nie moze odczytac zadnych rekordów z tabelki.
Odczytać może, ale nie te wstawione. ;)
Napisz może co masz na myśli tu: "Podczas tego importu chciałbym aby baza w zakresie danych przed rozpoczęciem importu była dostępna dla pozostałych użytkowników."
Import oznacza dodanie danych, aktualizacje czy usuwanie? A może mix tego wszystkiego?
Import danych oznacza: 1. Usunięcie części danych 2. Dodanie brakujących 2. Modyfikacji (aktualizacji) części rekordów już istniejących.
Chciałbym osiągnąć taki efekt, że jeśli przed rozpoczęciem importu tabelka Produkty miała np. 10 rekordów, to do zakończenia importu (czyli wykonania COMMIT) pozostali użytkownicy widzą te rekordy niezmienione. Import część z tych rekordów usunie, część zmieni a część zmodyfikuje, w rezultacie czego np. w tabeli pozostanie 5 rekordów niezmienionych, 3 zostaną skasowane, 2 zmodyfikowane, a 5 zostanie dodanych całkiem nowych. Tak przygotowane rekordy wystarczy jeśli będą dostępne po wykonaniu COMMIT.
Problem w tym, że jeśli mam READ_COMMITED, to do czasu wykonania COMMIT, jakikolwiek SELECT z tabelki Produkty "zawiesza" się. Jeśli w określonym czasie dotrze do serwera COMMIT, SELECT innego usera się wykona (zobaczy on tabelkę już po zmianach), jeśli natomiast nie zdąży - klient wykonujący SELECT z tej tabeli otrzyma wyjątek "Limit czasu przekroczony" zamiast pobrać rekordy, które były dostępne przed rozpoczęciem transakcji. Oczekiwany efekt do tej pory udało mi się osiągnąć tylko przy poziomie izolacji transakcji typu SNAPSHOT
Mam nadzieję, że teraz jest już jasne z czym mam problem :)
Pozdrawiam
Adam
Adam K.
Jedyne wyjaśnienie dlaczego tak się dzieje, jakie przychodzi mi do głowy, to takie, że aplikacja używa pojedynczego połączenia do bazy danych, zarówno dla importu jak i dla użytkowników. Wtedy rzeczywiście jeśli połączenie jest zajęte przez transakcję importową inne polecenia wydane na tym połączeniu "zwisną". Jeśli tak nie jest to nie wydaje mi się, aby opisane zachowanie było możliwe. Podstawą w bazach danych jest możliwość jednoczesnego dostępu do danych przez wielu użytkowników. A takie zachowanie oznaczało by to, że na raz z bazą może pracować dokładnie jedna osoba.
Pozdrawiam
Sebastian

odp A

Adam K. Witam, Użytkownik "Sławomir Szyszło" napisał w wiadomości Dnia Mon, 6 Jul +, "Adam K." wklepał(-a):
Jedyne wyjaśnienie dlaczego tak się dzieje, jakie przychodzi mi do głowy, to takie, że aplikacja używa pojedynczego połączenia do bazy danych, zarówno dla importu jak i dla użytkowników. Wtedy rzeczywiście jeśli połączenie jest zajęte przez transakcję importową inne polecenia wydane na tym połączeniu "zwisną". Jeśli tak nie jest to nie wydaje mi się, aby opisane zachowanie było możliwe. Podstawą w bazach danych jest możliwość jednoczesnego dostępu do danych przez wielu użytkowników. A takie zachowanie oznaczało by to, że na raz z bazą może pracować dokładnie jedna osoba.
Witam, Użytkownik "Sebastian Kolski" napisał w wiadomości []
Też dziwi mnie to zachowanie, ale testowałem to na różne sposoby: 1. Uruchomiłem dwa razy moją aplikację na tym samym komputerze, w jednej wywołałem rozpoczęcie transakcji, dodawanie rekordu (bez commita), na drugiej odpaliłem odczyt rekordów, który zawisnął do czasu otrzymania wyjątku "Upłynął limit czasu". 2. Uruchomiłem swoją aplikację, w niej rozpocząłem transakcję, dodawanie rekordu (także bez commita), uruchomiłem na tym samym komputerze Microsoft SQL Server Management Studio, podłączyłem się do tej samej bazy i wykonałem SELECT * FROM tabelka, i to polecenie zawisło do czasu COMMIT w mojej aplikacji. Swoje testy opieram na MSSQL Express Edition.
Pozdrawiam Adam

odp A

Te¿ dziwi mnie to zachowanie, ale testowa³em to na ró¿ne sposoby: 1. Uruchomi³em dwa razy moj± aplikacjê na tym samym komputerze, w jednej wywo³a³em rozpoczêcie transakcji, dodawanie rekordu (bez commita), na drugiej odpali³em odczyt rekordów, który zawisn±³ do czasu otrzymania wyj±tku "Up³yn±³ limit czasu". 2. Uruchomi³em swoj± aplikacjê, w niej rozpocz±³em transakcjê, dodawanie rekordu (tak¿e bez commita), uruchomi³em na tym samym komputerze Microsoft SQL Server Management Studio, pod³±czy³em siê do tej samej bazy i wykona³em SELECT * FROM tabelka, i to polecenie zawis³o do czasu COMMIT w mojej aplikacji. Swoje testy opieram na MSSQL Express Edition. A mo¿esz sprawdziæ z poziomu SQL jaki jest ustawiony poziom izolacji po zalogowaniu?

odp A

2. Uruchomiłem swoją aplikację, w niej rozpocząłem transakcję, dodawanie rekordu (także bez commita), uruchomiłem na tym samym komputerze Microsoft SQL Server Management Studio, podłączyłem się do tej samej bazy i wykonałem SELECT * FROM tabelka, i to polecenie zawisło do czasu COMMIT w mojej aplikacji. Użytkownik "Adam K." napisał w wiadomości
[]
Witaj w świecie rozległego blokowania rekordów ms sql To niestety nie Oracle, gdzie transakcje blokują dane "normalnie", czyli jedna transakcja robi insert/update/delete, druga transakcja robi select i "widzi" stan rekordów sprzed rozpoczęcia pierwszej transakcji (oczywiście mowa o select "read only" bez klauzuli "for update"). MS SQL ma przykry zwyczaj blokowania większego obszaru danych, niż tylko rekordy objęte transakcją, przy czym chyba żaden dokument nie wyjaśnia dokładnie, jak wyliczyć blokowany obszar danych. Spróbuj w swoim teście zmienić select * from tab na select kolumna from tab where id=1 (przy założeniu, że rekord o id=1 istnieje i nie został objęty niezakończoną transakcją) i jest szansa, że dane zostaną pobrane. Tu jest opisane msdn.microsoft.com/en-us/library/ms49.aspx jakie "gradacje" blokad zna sql server, ale prawdę mówiąc wiele z tego nie wynika - nie oszacujesz ile stron zajmują rekordy w bazie Generalnie trzeba dążyć, żeby transakcja była możliwie najkrótsza; może droga zaproponowana przez Sławka jest dobra - czyli ładowanie wstępne danych do tabel specjalnie wydzielonych, z których nie korzysta aplikacja, tam obróbka, a potem tylko możliwie najprostszy insert/update tak, aby dane w tabelach wykorzystywanych przez aplikację były blokowane przez możliwie krótki okres czasu. Izolacja transakcji na poziomie "snaphot" może pomóc, ale musiałbyś zmusić aplikację, aby też używała tego poziomu izolacji.

Dodaj odpowied¼

Tytu³:

Mail: (w celu weryfikacji posta)