Как бороться с утечкой уровней изоляции транзакций из пула соединений SQL ServerC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как бороться с утечкой уровней изоляции транзакций из пула соединений SQL Server

Сообщение Anonymous »

При использовании пула соединений Microsoft SQL Server при повторном использовании соединения все данные сеанса сбрасываются (например, удаляются временные таблицы). Внутренне это делается с помощью специальной процедуры sp_reset_connection. Этот ответ содержит полный список сбрасываемых данных — что делает sp_reset_connection. Одна примечательная вещь, которой нет в этом списке, — это уровень изоляции транзакций. Так, например, если соединение выполнило транзакцию на уровне чтение без фиксации и это соединение перезапускается, следующий поток, который получит это соединение, будет иметь уровень изоляции транзакции чтение без фиксации. , что отличается от значения по умолчанию для новых подключений прочитано зафиксировано. Такое поведение предусмотрено (Microsoft), как оно описано в спецификации TDS; там есть это предложение: «Распределенные
транзакции и уровни изоляции не будут сброшены.».
Это все предыстория. Есть еще несколько вопросов SO об уровнях изоляции ненадежных транзакций, но ни один из них не охватывает то, что я хочу знать...
  • один — Как предотвратить утечку уровень изоляции транзакций в соединениях пула
  • другое — SQL Server: уровень изоляции протекает через соединения пула
Учитывая, что Dapper и Entity Framework имеют общий шаблон открытия соединения перед выполнением одного запроса, а затем его закрытия, может показаться, что эти библиотеки ожидают использования пула соединений. В более широком смысле, когда объект SqlConnection начинается как закрытый, операторы EF и современные методы базы данных открывают соединение перед выполнением, а затем закрывают его после. Если соединение уже было открыто либо явно путем вызова Open, либо в качестве побочного эффекта запуска транзакции, то Dapper и EF используют соединение как есть (после этого они его не закрывают).
Поскольку этот общий шаблон используется Microsoft (и другими), это предполагает (на мой взгляд), что ожидается использование пула соединений. А для объекта SqlConnection даже включен пул соединений по умолчанию.
Поэтому этот уровень изоляции дырявых (или постоянных) транзакций может показаться крайне нелогичным. Это действительно ужасная ловушка для непосвященных. Если запрос необходимо выполнить как прочитанный без фиксации (или, что менее хлопотно, сериализованный), а затем невинно вернуть его в пул соединений, следующий поток может преподнести неприятный сюрприз.
Вот небольшой пример программы, демонстрирующей этот неприятный сюрприз:

Код: Выделить всё

private static void PoolTest()
{
for (int poolMode = 1; poolMode  item.MyValue == "UNEXPECTED");
// wait for the background thread (if there was one)
background?.Join();
}
if (scary)
Console.WriteLine($"{poolTest}/F: we got a dirty read, all unexpected-like; isn't that scary");
if (poolMode == 1)
Console.WriteLine();
}
}

// this is the test table, a simplification of tables used everywhere
private class Dto
{
public string? MyKey { get; set; }
public string? MyValue { get; set; }
public override string ToString() => $"{MyKey} {MyValue}";
}
Есть несколько решений этой проблемы. Ни один из них не идеален. Наиболее очевидным является сброс уровня изоляции транзакции соединения перед его закрытием или удалением и возвратом его в пул. В EF Core можно использовать перехватчик БД (

Код: Выделить всё

IDbConnectionInterceptor
), чтобы сделать это.
Я видел различные ответы, предлагающие использовать разные строки подключения для каждого предполагаемого уровня изоляции или просто никогда не использовать уровни изоляции вообще; они бесполезны за пределами игрушечных или очень маленьких программ.
Итак, вот мой актуальный вопрос:
Что намеревает Microsoft что нам делать? Каждый прямой пример, который я видел, подвержен этой утечке. Я видел, что в документации TDS указано такое поведение, но нет никаких намеков на то, почему это сделано именно так. Итак, почему пул соединений реализован таким образом, что новые и повторно используемые соединения имеют разное (и проблемное) поведение уровня изоляции транзакций по умолчанию?

Подробнее здесь: https://stackoverflow.com/questions/784 ... lation-lev
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»