Создание транзакций область с Новое sqlconnection в пределах существующего объекта sqlconnection, используя блок
Я хочу выполнить один запрос SELECT, за которым следует последовательность запросов UPDATE (Все в одной таблице); UPDATE реализуется в отдельном методе, который вызывается повторно. Если один из запросов обновления завершается неудачей, я хочу, чтобы все они завершились неудачей/откатом - поэтому я хочу включить их в транзакцию. Однако я не уверен, где SqlConnection
следует открывать, чтобы избежать каких-либо проблем. Моя текущая реализация выглядит следующим образом:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// execute a single SELECT here
using (TransactionScope scope = new TransactionScope())
{
for (int i=0; i<...; i++)
{
Update(); // UPDATE query
}
scope.Complete();
}
}
Update()
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// execute a single UPDATE here
}
}
Должно ли это работать так, как ожидается, во всех ситуациях?
Все в порядке чтобы открыть соединение перед выбором, затем откройте новое соединение в методе Update()
? Из-за объединения соединений одно и то же соединение будет использоваться для запросов SELECT и UPDATE (connectionString
является одним и тем же), но только запросы UPDATE будут зачислены в транзакцию, верно? Но что происходит, если в Update()
используется другое соединение? Будут ли все запросы обновления по-прежнему включаться в транзакцию, как ожидалось, и выполняться атомарно?
Если я правильно понимаю, создание области транзакций после закрытие первого соединения (после блока using
, который выполняет SELECT) все еще будет работать, но снизит производительность, потому что соединение будет закрыто и его нужно будет снова открыть, правильно? Или на самом деле создается новое соединение для области транзакции, которое открывается и закрывается каждый раз, когда вызывается Update()
?
1 ответ:
Из-за объединения соединений одно и то же соединение будет использоваться как для запросов SELECT, так и для запросов UPDATE
Нет, этого не произойдет; это может произойти только в том случае, если вы сначала отпустите соединение обратно в пул - в настоящее время у вас есть два соединения одновременно, поэтому это не может быть одно и то же. Вам нужно немного перестроиться:
using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); // execute a single SELECT here } // <==== end the first connection using (TransactionScope scope = new TransactionScope()) { for (int i=0; i<...; i++) { Update(); // UPDATE query } scope.Complete(); }
Создание области транзакции после закрытия первого соединения (...) но снизит производительность, потому что подключение был бы закрыт и должен быть вновь открыт, правильно
Нет; когда вы" закрываете " его, вы фактически просто отпускаете его обратно в пул; он не закрывает базовое соединение (если только у вас не отключен пул). Закрытие (или, по крайней мере, удаление) является нормальным и ожидаемым.
Но только запросы обновления будут зачислены в транзакцию, верно?
Правильно, потому что тогда это единственное место, где соединение открывается внутри области транзакции
Но что произойдет, если в Update () будет использовано другое соединение? Будут ли все запросы обновления по-прежнему включаться в транзакцию, как ожидалось, и выполняться атомарно?
Все соединения, поддерживающие подключение (при условии, что оно не отключено в строке подключения), будут подключены. Однако в зависимости от сервера он может использовать LTM или DTC. Если вы хотите быть уверены в своих связях: возьмите их под свой контроль:
using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); // execute a single SELECT here } // <==== end the first connection using (TransactionScope scope = new TransactionScope()) using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); for (int i=0; i<...; i++) { Update(connection); // UPDATE query } scope.Complete(); }
Обратите внимание, что я передаю
connection
вUpdate
в выше; здесь очевидно , что будет использоваться одно соединение (при условии, чтоUpdate
работает нормально).