← Назад к вопросам

Что такое транзакции?

1.0 Junior🔥 61 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Транзакции в контексте баз данных и C# Backend

Транзакция — это логическая единица работы с данными, которая состоит из последовательности операций (например, чтения, записи, изменения), выполняемых как одно целое. Основная цель — обеспечить ACID-свойства, гарантируя корректность и надежность данных даже в условиях ошибок, параллельного выполнения или системных сбоев.

Ключевые свойства ACID

  • Atomicity (Атомарность): Транзакция выполняется как единое целое. Все её операции либо выполняются полностью, либо не выполняются вовсе. Если происходит ошибка на любом шаге, система откатывает (rollback) все изменения к исходному состоянию.
  • Consistency (Согласованность): Транзакция переводит систему из одного согласованного состояния в другое. Она не нарушает бизнес-правила, инварианты и ограничения (например, уникальность, ссылочную целостность).
  • Isolation (Изолированность): Выполняющиеся параллельно транзакции не влияют на друг друга. Их промежуточные результаты скрыты от других транзакций до завершения. Это предотвращает проблемы параллельного доступа.
  • Durability (Долговременность): После успешного завершения (commit) изменения, сделанные транзакцией, становятся постоянными и сохраняются в системе даже после сбоев (например, перезагрузки сервера).

Проблемы параллельного доступа и уровни изоляции

При одновременном выполнении нескольких транзакций могут возникать конфликты. Чтобы управлять степенью изоляции и балансировать между безопасностью и производительностью, существуют уровни изоляции (в контексте SQL и ADO.NET/Entity Framework):

  • Read Uncommitted: Самый низкий уровень. Транзакция может читать незафиксированные данные других транзакций. Возможны проблемы "грязного" чтения (Dirty Read).
  • Read Committed: Транзакция читает только зафиксированные данные. Предотвращает "грязное" чтение, но возможны проблемы несовпадающего чтения (Non-repeatable Read).
  • Repeatable Read: Гарантирует, что если транзакция читает строку, она не сможет быть изменена другой транзакцией до завершения первой. Предотвращает несовпадающее чтение, но возможны проблемы чтения фантомных строк (Phantom Read).
  • Serializable: Самый высокий уровень. Транзакции выполняются так, как если бы они выполнялись последовательно, одна за другой. Полностью предотвращает все конфликты, но значительно снижает производительность.

Работа с транзакциями в C# и ADO.NET

Базовый пример использования транзакции при работе с SQL Server через SqlConnection:

using System.Data.SqlClient;

public void TransferFunds(int fromAccountId, int toAccountId, decimal amount)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        // Начало транзакции
        SqlTransaction transaction = connection.BeginTransaction("FundsTransfer");

        try
        {
            using (SqlCommand debitCommand = new SqlCommand(
                "UPDATE Accounts SET Balance = Balance - @Amount WHERE Id = @FromId",
                connection, transaction))
            {
                debitCommand.Parameters.AddWithValue("@Amount", amount);
                debitCommand.Parameters.AddWithValue("@FromId", fromAccountId);
                debitCommand.ExecuteNonQuery();
            }

            using (SqlCommand creditCommand = new SqlCommand(
                "UPDATE Accounts SET Balance = Balance + @Amount WHERE Id = @ToId",
                connection, transaction))
            {
                creditCommand.Parameters.AddWithValue("@Amount", amount);
                creditCommand.Parameters.AddWithValue("@ToId", toAccountId);
                creditCommand.ExecuteNonQuery();
            }

            // Фиксация транзакции
            transaction.Commit();
            Console.WriteLine("Транзакция успешно завершена.");
        }
        catch (Exception ex)
        {
            // Откат транзакции в случае ошибки
            transaction.Rollback();
            Console.WriteLine("Транзакция откачена. Ошибка: " + ex.Message);
            throw;
        }
    }
}

Транзакции в Entity Framework Core

В EF Core управление транзакциями более гибкое и может быть явным или автоматическим.

using Microsoft.EntityFrameworkCore;

public class OrderService
{
    private readonly AppDbContext _context;

    public async Task CreateOrderWithTransaction(Order order, List<OrderItem> items)
    {
        // Использование транзакции с помощью DbContext
        using (var transaction = await _context.Database.BeginTransactionAsync())
        {
            try
            {
                // Операция 1: Сохранить заказ
                _context.Orders.Add(order);
                await _context.SaveChangesAsync();

                // Операция 2: Сохранить позиции заказа
                foreach (var item in items)
                {
                    item.OrderId = order.Id;
                    _context.OrderItems.Add(item);
                }
                await _context.SaveChangesAsync();

                // Фиксация транзакции
                await transaction.CommitAsync();
            }
            catch (Exception)
            {
                // Откат в случае любой ошибки
                await transaction.RollbackAsync();
                throw;
            }
        }
    }
}

EF Core 5+ также поддерживает явное управление транзакциями через TransactionScope (для распределенных транзакций в ограниченных сценариях) и автоматическое создание транзакции при каждом вызове SaveChangesAsync() (неявная транзакция).

Распределенные транзакции и паттерн Unit of Work

В сложных системах, где операция затрагивает несколько разных баз данных или ресурсов (например, SQL Server + Redis + отправка сообщения в очередь), используются более сложные подходы:

  • Паттерн Unit of Work: Объект, который отслеживает все изменения в рамках бизнес-операции и фиксирует их как единую транзакцию. Часто реализуется в ORM (как DbContext в EF Core).
  • Сложности распределенных транзакций: Полная поддержка распределенных транзакций (например, через TransactionScope) в современных микросервисных архитектурах часто считается антипаттерном из-за проблем с производительностью, надежностью и сложностью координации. Вместо этого используются согласованные по конечному состоянию (eventually consistent) подходы: компенсирующие транзакции, Saga паттерн (Choreography или Orchestration) и асинхронная обработка событий через message broker (Kafka, RabbitMQ).

Заключение

Таким образом, понимание транзакций в C# Backend разработке критически важно для построения надежных и корректных систем. Это включает не только знание базовых механизмов ADO.NET и Entity Framework, но также понимание компромиссов при выборе уровней изоляции и современных подходов к управлению сложными операциями в распределенных системах, где классические распределенные транзакции часто заменяются на более гибкие архитектурные паттерны.