@saneok44

C# SqlTransaction блочит таблицу, как обойти блокировку или что делаю не так?

Есть "мелкие" методы которые подключаются к базе получают значение и закрывают подключение.

Есть две SQLCommand последовательные.

1. Создаю подключение.
2. Бидню транзакцию к подключению.
2.1. Биндю команду к подключению и транзакции.
3. Исполняю первую команду command_1.ExecuteNonQuery();
4. Хочу получить значение из тб. вызывая "мелкие" метод. И он вываливается по таймауту.
5. До исполнения второй команды разумеется дело не дошло.

Окей меняю мелкий метод передавая ему транзакцию и коннект, чтобы он стал частью транзакции.
Снова выполняю пункты 1., 2., 2.1, 3.
4. Теперь мелкий метод став частью транзакции получает значение из тб.
5. Выполняю command_2.ExecuteNonQuery();
6. transaction.Commit();

После исполнения первой транзакции и до выполнения второй заметил что блочится вся таблица и все коннекты и запросы вываливаются по таймауту. Я даже на момент транзакции запустил sql management studio и не смог выполнить запрос, пока транзакция на C# не закончилась. Ну я тут подумал хм ... транзакция блочит тб да как то странно ...

Открыл sql management studio вставил первую команду и до commit сделал задержку в 1 минуту.
begin transaction
...
WAITFOR DELAY '00:01';
commit transaction
Затем выполнил параллельно другую команду и она спокойно выполнилась до того как закоммитилась первая команда.

Вот и я не понимаю, почему с# транзакция блочит таблицу. Когда те же самые операции делаю через sql management studio без всяких блокировок.

Игрался с уровнями блокировок connection.BeginTransaction(IsolationLevel.....) ни к чему это не привело. Как блочилась вся тб так и блочится и ни одна учетка не может выполнить запрос без завершения транзакции.

Краткий листинг:
SqlConnection connection = new SqlConnection(ark.stringConnect);
connection.Open();
SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.......);
SqlCommand command1 = _Delete(userID, periodID);
command1.CommandTimeout = 60;
command1.Connection = connection;
command1.Transaction = transaction;
command1.ExecuteNonQuery();

string S = "мелкий_метод(получить какое то значение)" он делает новое подключение и получает значение

SqlCommand command2 = Command_UpdateCascadePeriod(userID, uPeriod);
command2.CommandTimeout = 60;
 command2.Connection = connection;
command2.Transaction = transaction;
command2.ExecuteNonQuery();

transaction.Commit();
  • Вопрос задан
  • 103 просмотра
Пригласить эксперта
Ответы на вопрос 2
@mvv-rus
Настоящий админ AD и ненастоящий программист
Игрался с уровнями блокировок connection.BeginTransaction(IsolationLevel.....) ни к чему это не привело.

Попробуйте обе транзации - и основную, и в мелком методе - делать с уровнем изоляции Snapshot.
По умолчанию изоляция транзакций в MS SQL реализуется через блокировки (изначально - обрабатываемых записей, но может переползти и на всю таблицу).
А вообще, при работе с незакрытй транзакциейоя бы передавал в мелкий метод то подключение, на котором открыта транзакция, чтобы он работал с ней. Можно сделать этот параметр необязательным (null по умолчанию) и в случае, если он не передан - открывать дополнительное подключение.
Ответ написан
@saneok44 Автор вопроса
Пока что путь решения такой. Мелкие методы переписал в два режима работы: режим своего подключения без транзакции и в режиме как часть транзакции. Все мелкие запросы лежат у меня в отдельном классе он у меня как базовый класс. Докинул в него два свойства SQLConnection и SQLTransaction. По ним мелкие методы определяют как им выполнить команду, в режиме транзакции или в обычном режиме своего подключения без транзакции (можно сказать грязное чтение и запись). Так же есть тематические расширенные классы которые наследуют этот базовый класс. Если методу в расширенном классе нужно отработать как транзакция внутри этого метода используя using задаю SQLConnection и SQLTransaction и внутри этого блока присваиваю свойствам SQLConnection И SQLTransaction которые унаследовал расширенный класс от базового класса, ссылку на коннект и на транзакцию и теперь мелкие методы работают как часть одной транзакции. Мне не нужны режимы Снепшота или другие изоляции главное назначение транзакции это гарантия выполнения частей команд в целом.
До всего этого у меня мелкие методы работали с базой независимо друг от друга и при крахе одной из них я не гарантировал целостности данных. Так как появилась необходимость в гарантии целостности так как команда 1 и 2 сами по себе делают много операции внутри себя, а вторая команда вообще зависит от успеха выполнения первой то и появилась необходимость в транзакции.

Я не стал все мелкие методы переписывать в режи транзакции так как это не целесообразно да и вообще мне кажется ресурсозатратно. Допустим у меня есть объект сlass People у него 10 свойств, и (~) на каждое свойство у меня метод на получение его из базы (да у нас база находится на одном сервере с проектами) это получается 10 транзакций ... да можно сделать так чтобы получить все свойства одним запросом, но не всегда это надо получать все свойства. Короче как то так. Таблиц у нас всего 5 описывающие объект. Таблица Классов, Таблица Свойств, Таблица Обектов (тела уникальных объектов) и Таблица Свойства объектов ну и Таблица Логи.

Если кому то покажется дичью прошу высказаться интересно мнение (только по существу)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы