Основной поток серверного вызова всегда выполняется в одной транзакции от начала и до конца:
Исключение на любом этапе обработки запроса приведет к откату всей транзакции. Однако, выполнение DDL запросов (например, CREATE, ALTER, DROP) зафиксирует транзакцию, что может привести к нестабильному поведению системы. Поэтому такие запросы (DDL или же запросы, требующие промежуточной фиксации по иной причине) следует выполнять в отдельной транзакции.
Также может возникнуть ситуация, когда в рамках одного серверного вызова необходимо зафиксировать какую-либо операцию. Например, при выполнении запроса, изменяющего больше количество строк (пересчета цен), для сокращения длительности возможных блокировок можно разбить его на несколько частей, изменяя по 100 строк за раз, и выполнять каждую часть в отдельной транзакции, фиксируя ее.
Чтобы открыть новую транзакцию в рамках одного серверного вызова, следует использовать класс TransactionScopeBuilder (из пространства имен Ultima.Server.Data):
// Очистка содержимого таблицы. using (var scope = TransactionScopeBuilder.CreateTransactionScope()) { var sql = @"DELETE TABLE TEMP_CALCULATIONS"; SqlService.Execute(sql); scope.Complete(); } |
В приведенном примере независимо от результатов серверного вызова весь блок внутри using будет зафиксирован в базе как единая операция.
Использование метода Complete указывает, что все операции в области успешно завершены. Использование метода Dispose завершает область транзакции, и если перед этим не был использован метод Complete, все операции в области откатываются.
Уровень изоляции созданной с помощью TransactionScopeBuilder транзакции будет read commited. Если необходимо создать транзакцию с уровнем изоляция serializable, можно использовать класс TransactionScope (подробное описание класса можно найти на сайте MSDN eng/rus):
using (var ts = new TransactionScope(TransactionScopeOption.RequiresNew)) |
Однако рекомендуемым является первый вариант с TransactionScopeBuilder.