SqlDataAdapter.Fill () в SqlTransaction - это плохая практика? - PullRequest
1 голос
/ 09 июня 2011

Поскольку у меня есть класс «DB util» с методом DataSet QueryDB(string spName, DBInputParams inputParams), который я использую для всех своих обращений к базе данных, я хотел бы повторно использовать этот метод для поддержки транзакционных вызовов.

Итак, в конце у меня будет SqlDataAdapter.Fill внутри SqlTransaction. Будет ли это плохой практикой? Потому что редко я вижу использование DataAdapter.Fill внутри транзакции и чаще ExecuteReader (). Есть ли подвох?

Edit1: Дело в том, что внутри моей транзакции часто требуется также получать некоторые данные (например, автоидентификаторы) ... вот почему я хотел бы получить их как DataSet.

Edit2: Странно, когда я использую этот подход в цикле for (10000) из 2 разных процессов, я получаю «Транзакция (ID процесса 55) заблокирована на ресурсах блокировки с другим процессом и была заблокирована выбран жертвой тупика. Перезапустите транзакцию. " , Это правильное поведение?

Edit3: (ответ для Edit2) Я использовал IDENT_CURRENT('XTable'), который был источником ошибки. После того, как я вернулся к SCOPE_IDENTITY(), все было решено.

Ответы [ 2 ]

2 голосов
/ 09 июня 2011

Это не плохая практика.Следует помнить одну вещь: все операторы будут использовать неявную транзакцию, которую они будут автоматически фиксировать, когда оператор закончится.То есть SELECT (как в SELECT, используемом Fill) будет всегда использовать транзакцию, вопрос в том, придется ли ей запускать ее самостоятельно или она будет использовать существующую.

Есть ли разница между количеством, типом и продолжительностью блокировок, полученных SELECT в неявной транзакции, и явной транзакцией?В модели транзакции по умолчанию (READ COMMITTED изоляция) NO ее нет.Поведение идентично и неразличимо.При других уровнях изоляции (повторяемое чтение, сериализация) существует различие, но оно является необходимым для достижения желаемого более высокого уровня изоляции, и использование явной транзакции - это только способ достижения этого желаемого уровня изоляции, при необходимости.

Кроме того, если SELECT должен прочитать результаты ожидающей транзакции (еще не зафиксированной), как в вашем примере (считывание сгенерированных идентификаторов), тогда нетДругой способ .SELECT должен быть частью транзакции, сгенерировавшей идентификаторы, в противном случае он не сможет увидеть эти незафиксированные идентификаторы!

Однако следует соблюдать осторожность.Я полагаю, что в вашем распоряжении прекрасный инструмент, который может значительно облегчить обработку всех транзакций: System.Transactions .Весь код ADO.Net учитывает системные транзакции и автоматически регистрирует любое соединение и команду в ожидающей транзакции, если вы просто объявите TransactionScope.То есть, если функция Foo объявляет TransactionScope и затем вызывает функцию Bar, если Bar выполняет любое ADO.Net operatio, она автоматически будет частью транзакции, объявленной в Foo, даже если Bar делает ничего явно.TransactionScope подключается к контексту потока, и все вызовы ADO.Net, вызываемые Bar, автоматически проверяют этот контекст и используют его.Обратите внимание, что я действительно имею в виду любой вызов ADO.Net, включая вызовы провайдера Oracle.Увы, хотя есть предупреждение: с использованием нового TransactionScope () Считается вредным : конструктор по умолчанию TransactionScope создаст сериализуемую транзакцию, которая является избыточной.Вы должны использовать конструктор, который принимает объект TransactionOptions и изменить поведение на ReadCommitted.Второй недостаток TransactionScope заключается в том, что вы должны быть очень осторожны при управлении соединениями: если вы открываете более одного соединения в области действия, они будут зарегистрированы в распределенной транзакции, которая медленная и требует настройки MSDTC,и приводит ко всем видам трудно отлаживаемых ошибок.Но в целом я упал, что преимущества использования TransactionScope перевешивают проблемы, и полученный код всегда более элегантен, чем явный обход IDbTransaction.

2 голосов
/ 09 июня 2011

Это плохая практика, потому что пока транзакция открыта, записи / страницы / таблицы, в которые вы вносите изменения, блокируются на время транзакции.Заполнение просто заставляет весь процесс держать эти ресурсы заблокированными дольше.В зависимости от ваших настроек sql, это может заблокировать другие доступы к этим ресурсам.

При этом, если это необходимо, необходимо просто реализовать штраф за это.

...