У меня есть запрос на чтение, который я выполняю в транзакции, чтобы я мог указать уровень изоляции. Что мне делать после завершения запроса?
- Зафиксировать транзакцию
- Откатить транзакцию
- Ничего не делать (что приведет к откату транзакции в конце блока using)
Каковы последствия каждого из них?
using (IDbConnection connection = ConnectionFactory.CreateConnection())
{
using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
{
using (IDbCommand command = connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandText = "SELECT * FROM SomeTable";
using (IDataReader reader = command.ExecuteReader())
{
// Read the results
}
}
// To commit, or not to commit?
}
}
EDIT: вопрос не в том, следует ли использовать транзакцию или есть ли другие способы установить уровень транзакции. Вопрос в том, имеет ли значение то, что транзакция, которая ничего не изменяет, фиксируется или откатывается. Есть разница в производительности? Влияет ли это на другие подключения? Есть ли другие отличия?
sql
database
transactions
Стефан Мозер
источник
источник
Ответы:
Вы совершаете. Период. Другой разумной альтернативы нет. Если вы начали транзакцию, вы должны ее закрыть. Фиксация снимает любые блокировки, которые у вас могли быть, и одинаково разумна с уровнями изоляции ReadUncommitted или Serializable. Полагаться на неявный откат - хотя, возможно, это технически эквивалентно - это просто плохой тон.
Если вас это не убедило, просто представьте следующего человека, который вставляет оператор обновления в середину вашего кода и должен отслеживать происходящий неявный откат и удалять свои данные.
источник
Если вы ничего не меняли, вы можете использовать COMMIT или ROLLBACK. Любой из них снимет любые блокировки чтения, которые вы приобрели, и, поскольку вы не внесли никаких других изменений, они будут эквивалентными.
источник
Если вы начинаете транзакцию, лучше всего всегда ее фиксировать. Если в вашем блоке использования (транзакции) возникнет исключение, транзакция будет автоматически отменена.
источник
IMHO может иметь смысл обернуть запросы только для чтения в транзакции, поскольку (особенно в Java) вы можете указать транзакции, чтобы она была «только для чтения», что, в свою очередь, драйвер JDBC может рассмотреть возможность оптимизации запроса (но не обязательно, поэтому никто все же помешает вам выдать
INSERT
). Например, драйвер Oracle полностью избегает блокировок таблиц для запросов в транзакции, помеченной только для чтения, что дает большую производительность в приложениях, ориентированных на чтение.источник
Рассмотрим вложенные транзакции .
Большинство СУБД не поддерживают вложенные транзакции или пытаются имитировать их очень ограниченным образом.
Например, в MS SQL Server откат внутренней транзакции (которая не является реальной транзакцией, MS SQL Server просто считает уровни транзакций!) Откатит все, что произошло в самой внешней транзакции (которая является реальной транзакцией).
Некоторые оболочки базы данных могут рассматривать откат внутренней транзакции как признак того, что произошла ошибка, и откатывать все в самой внешней транзакции, независимо от того, была ли завершена последняя транзакция или откат.
Таким образом, COMMIT - это безопасный способ, когда вы не можете исключить, что ваш компонент используется каким-либо программным модулем.
Обратите внимание, что это общий ответ на вопрос. Этот пример кода умело решает проблему с внешней транзакцией, открывая новое соединение с базой данных.
Что касается производительности: в зависимости от уровня изоляции, SELECT может потребовать различной степени БЛОКИРОВКИ и временных данных (снимков). Это очищается при закрытии транзакции. Не имеет значения, выполняется ли это через COMMIT или ROLLBACK. Может быть незначительная разница в затраченном времени ЦП - COMMIT, вероятно, обрабатывается быстрее, чем ROLLBACK (на два символа меньше) и другие незначительные отличия. Очевидно, это верно только для операций только для чтения!
Совершенно не запрашивается: другой программист, который может прочитать код, может предположить, что ОТКАТ подразумевает состояние ошибки.
источник
Небольшое примечание, но вы также можете написать этот код следующим образом:
И если вы немного реструктурируете вещи, вы также сможете переместить блок using для IDataReader наверх.
источник
Если вы поместите SQL в хранимую процедуру и добавите это над запросом:
тогда вам не нужно прыгать через обручи в коде C #. Установка уровня изоляции транзакции в хранимой процедуре не приводит к тому, что параметр применяется ко всем будущим применениям этого соединения (о чем вам нужно беспокоиться с другими настройками, поскольку соединения объединены в пул). В конце хранимой процедуры он просто возвращается к тому, чем было инициализировано соединение.
источник
ROLLBACK обычно используется в случае ошибки или исключительных обстоятельств, а COMMIT - в случае успешного завершения.
Мы должны закрывать транзакции с помощью COMMIT (для успеха) и ROLLBACK (для сбоя), даже в случае транзакций только для чтения, где это не имеет значения. На самом деле это имеет значение для последовательности и защиты от будущего.
Транзакция только для чтения может логически «потерпеть неудачу» по многим причинам, например:
Если COMMIT и ROLLBACK используются правильно для транзакции только для чтения, она продолжит работать должным образом, если в какой-то момент будет добавлен код записи DB, например, для кэширования, аудита или статистики.
Неявный ROLLBACK следует использовать только в ситуациях «фатальной ошибки», когда приложение вылетает из строя или завершается с неисправимой ошибкой, сбоем сети, отключением питания и т. Д.
источник
Учитывая, что READ не меняет состояние, я бы ничего не делал. Выполнение фиксации ничего не даст, кроме как потратить цикл на отправку запроса в базу данных. Вы не выполнили операцию, изменившую состояние. Так же и с откатом.
Однако вы должны обязательно очистить свои объекты и закрыть подключения к базе данных. Не закрытие ваших соединений может привести к проблемам, если этот код вызывается повторно.
источник
Если вы установите AutoCommit false, то ДА.
В эксперименте с JDBC (драйвером Postgresql) я обнаружил, что если запрос выбора прерывается (из-за тайм-аута), вы не можете инициировать новый запрос выбора, если не откатитесь.
источник
В вашем примере кода, где у вас есть
// Сделаем что-нибудь полезное
Вы выполняете оператор SQL, который изменяет данные?
Если нет, то не существует такой вещи, как «Чтение» транзакции ... Только изменения из операторов Insert, Update и Delete (операторов, которые могут изменять данные) находятся в транзакции ... То, о чем вы говорите, - это блокировки, которые SQL Сервер помещает данные, которые вы читаете, из-за ДРУГИХ транзакций, которые влияют на эти данные. Уровень этих блокировок зависит от уровня изоляции SQL Server.
Но вы не можете зафиксировать или откатить что-либо, если ваш оператор SQL ничего не изменил.
Если вы изменяете данные, вы можете изменить уровень изоляции без явного запуска передачи ... Каждый отдельный оператор SQL неявно присутствует в транзакции. явный запуск транзакции необходим только для того, чтобы убедиться, что 2 или более операторов находятся в одной транзакции.
Если все, что вы хотите сделать, это установить уровень изоляции транзакции, просто установите для CommandText команды значение «Установить уровень изоляции транзакции, повторяющееся чтение» (или любой другой уровень, который вы хотите), установите для CommandType значение CommandType.Text и выполните команду. (вы можете использовать Command.ExecuteNonQuery ())
ПРИМЕЧАНИЕ. Если вы выполняете НЕСКОЛЬКО операторов чтения и хотите, чтобы все они «видели» то же состояние базы данных, что и первый, то вам необходимо установить верхний уровень изоляции Repeatable Read или Serializable ...
источник
Вам нужно запретить другим читать те же данные? Зачем использовать транзакцию?
@Joel - Мой вопрос лучше сформулировать как «Зачем использовать транзакцию для запроса чтения?»
@Stefan - Если вы собираетесь использовать AdHoc SQL, а не хранимую процедуру, просто добавьте WITH (NOLOCK) после таблиц в запросе. Таким образом, вы не несете накладных расходов (хотя и минимальных) в приложении и базе данных для транзакции.
РЕДАКТИРОВАТЬ @ Комментарий 3: Поскольку в тегах вопросов указано «sqlserver», я предположил, что MSSQLServer был целевым продуктом. Теперь, когда этот момент прояснился, я отредактировал теги, чтобы удалить конкретную ссылку на продукт.
Я до сих пор не уверен, почему вы вообще хотите совершить транзакцию по операции чтения.
источник