@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();
  • Вопрос задан
  • 127 просмотров
Пригласить эксперта
Ответы на вопрос 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 описывающие объект. Таблица Классов, Таблица Свойств, Таблица Обектов (тела уникальных объектов) и Таблица Свойства объектов ну и Таблица Логи.

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

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

Похожие вопросы