Изолиране на моментна снимка в SQL / код, блокиращ четения

Подозирам, че не разбирам напълно какво се случва или се случва нещо странно. (Първият случай е по-вероятен според мен.)

Голямата картина:

  • Опитвам се да накарам уеб услуга да изпълнява определени операции асинхронно, тъй като те могат да отнемат време и не искам клиентът да чака операциите да приключат (просто от време на време правете заявка за резултатите, за да видите операцията е Свършен).
  • Асинхронният код е обвит в транзакция - в случай че нещо се обърка, искам да мога да върна всички промени назад.
  • За съжаление последната стъпка от асинхронния код е да се извика РАЗЛИЧНА услуга, която отправя запитвания към същата база данни.
  • Въпреки опаковането на цялото нещо в транзакция за моментна снимка, последната стъпка е неуспешна, тъй като услугата не може да чете от базата данни.
  • По този въпрос, докато асинхронната операция е в ход, не мога да изпълня и прости оператори SELECT от базата данни.

Ето извадка от кода, който в момента използвам, за да тествам транзакциите (първо като използвам модела на Entity Framework 5):

        using (var transaction = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.RequiresNew, new System.Transactions.TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.Snapshot }))
        {
            var db = new DataModelContainer();
            Log test = new Log();
            test.Message = "TEST";
            test.Date = DateTime.UtcNow;
            test.Details = "asd";
            test.Type = "test";
            test.StackTrace = "asd";
            db.LogSet.Add(test);
            db.SaveChanges();
            using (var suppressed = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Suppress))
            {
                var newDb = new DataModelContainer();
                var log = newDb.LogSet.ToArray();  //deadlock here... WHY?
            }
            test = db.LogSet.Where(l => l.Message == "TEST").Single();
            db.LogSet.Remove(test);
            db.SaveChanges();
            transaction.Complete();
        }

Кодът създава прост запис в дневника в базата данни (да, в момента си играя, така че стойностите са боклук). Настроих SQL базата данни да позволява изолиране на моментни снимки и доколкото ми е известно, четенията все още трябва да бъдат разрешени (те се тестват в този код чрез използване на нова, потисната транзакция и нов DataModelContainer). Не мога обаче да направя заявка за LogSet в потиснатата транзакция или в SQL Management Studio - цялата таблица е заключена!

Така че, защо? Защо е заключен, ако обхватът на транзакцията е дефиниран като такъв? Опитах и ​​други нива на изолация (като ReadUncommited) и все още не мога да направя запитване към таблицата.

Може ли някой да даде обяснение за това поведение?


person Shaamaan    schedule 24.01.2014    source източник
comment
активирана ли е изолацията на моментни снимки във вашата база данни? Изолирането на моментна снимка трябва да бъде активирано чрез задаване на опцията за база данни ALLOW_SNAPSHOT_ISOLATION ON, преди да се използва в транзакции   -  person Moho    schedule 24.01.2014
comment
@Moho Да, така е. Настроих SQL базата данни да позволява изолиране на моментни снимки. Както и да е, проблемът продължава, когато се използват ДРУГИ режими на изолация (по-малко ограничителни от Serializable), като ReadUncommited, а този дори не се нуждае от изолиране на моментни снимки, активирано на SQL сървъра!   -  person Shaamaan    schedule 24.01.2014


Отговори (1)


В SSMS задайте текущото си ниво на изолация на SNAPSHOT и вижте дали това коригира проблема ви - вероятно е зададено на READ COMMITTED и следователно все още ще блокира поради чакащи актуализации.

Актуализация:

Можете да разрешите на READ COMMITTED достъп до версионни редове в цялата DB, като промените следната опция (и избягвате да се налага постоянно да задавате текущото ниво на изолация на SNAPSHOT):

ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
person Moho    schedule 24.01.2014
comment
Има чувството, че настройката за ниво на изолация в C# изобщо не се използва. Изолацията на моментна снимка е само краен пример, при който не трябва да се случва заключване, но проблемът е и с други нива на изолация. Проверете актуализирания код на C# - на този етап не е необходимо да използвам SSMS за извършване на тестовете. Освен това, настройката READ_COMMITTED_SNAPSHOT е частично решение - както беше посочено, тя не обяснява защо изолацията на транзакцията не е правилно зададена (ако изобщо е зададена). - person Shaamaan; 24.01.2014
comment
какви са нивата на изолация на другите ви сесии ИМА значение, както казах в решението. Ако сте настроени на READ COMMITTED - ще се заключи, докато не извършите промените. Това е цялата цел на настройката READ_COMMITTED_SNAPSHOT - да се предотврати блокиране, докато се чака SNAPSHOT ангажимент - person Moho; 24.01.2014
comment
Ааа, мисля, че виждам какъв е проблемът. Останах с впечатлението, че трябва изрично да отворя транзакция (при изпълнение на проста SELECT SSMS заявка, например). - person Shaamaan; 24.01.2014