Обработка ошибок фиксации транзакций

Примечание

EF 6.1 только в сторону — функции, API и т. д., обсуждаемые на этой странице, появились в Entity Framework 6,1. При использовании более ранней версии могут быть неприменимы некоторые или все сведения.

В рамках 6,1 мы представляем новую функцию обеспечения устойчивости подключений для EF: возможность обнаружения и восстановления автоматически при неустранимых сбоях подключения, влияющих на подтверждение фиксаций транзакций. полные сведения о сценарии лучше всего описаны в записи блога База данных SQL подключения и проблемы с идемпотентности. В целом, сценарий состоит в том, что при возникновении исключения во время фиксации транзакции существует две возможные причины.

  1. Сбой фиксации транзакции на сервере
  2. Транзакция успешно завершена на сервере, но возникла ошибка подключения, препятствующая уведомлению об успешном завершении клиента

Когда в первой ситуации возникает приложение или пользователь может повторить операцию, но во втором случае следует избегать повторных попыток, и приложение может восстановиться автоматически. Проблема заключается в том, что без возможности обнаруживать фактическую причину возникновения исключения во время фиксации приложение не может выбрать правильный курс действия. Новая функция в EF 6,1 позволяет с помощью EF проверить базу данных, если транзакция прошла удачно, и сделать правильный курс действий прозрачным.

Использование компонента

Чтобы включить эту функцию, необходимо включить вызов сеттрансактионхандлер в конструкторе DbConfiguration. Если вы не знакомы с DbConfiguration, см. раздел Конфигурация на основе кода. Эта функция может использоваться в сочетании с автоматическими повторными попытками, представленными в EF6, что помогает в ситуации, когда транзакция на самом деле не зафиксирована на сервере из-за временной ошибки.

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.SqlServer;

public class MyConfiguration : DbConfiguration  
{
  public MyConfiguration()  
  {  
    SetTransactionHandler(SqlProviderServices.ProviderInvariantName, () => new CommitFailureHandler());  
    SetExecutionStrategy(SqlProviderServices.ProviderInvariantName, () => new SqlAzureExecutionStrategy());  
  }  
}

Как осуществляется трассировка транзакций

Если эта функция включена, EF автоматически добавит новую таблицу в базу данных с именем __Transactions. Новая строка вставляется в эту таблицу каждый раз при создании транзакции EF, и эта строка проверяется на существование, если во время фиксации происходит сбой транзакции.

Хотя EF будет лучше удалять строки из таблицы, когда они больше не нужны, таблица может расти, если приложение завершается преждевременно и по этой причине может потребоваться очистить таблицу вручную в некоторых случаях.

Как справляться со сбоями фиксации в предыдущих версиях

До EF 6,1 не существовало механизма по обработке ошибок фиксации в продукте EF. Существует несколько способов работы с этой ситуацией, которые можно применить к предыдущим версиям EF6:

  • Вариант 1. ничего не предпринимать

    Вероятность сбоя подключения во время фиксации транзакции мала, поэтому приложение может быть вполне неудачным, если это условие действительно происходит.

  • Вариант 2. Использование базы данных для сброса состояния

    1. Отменить текущий DbContext
    2. Создание нового DbContext и восстановление состояния приложения из базы данных
    3. Сообщите пользователю о том, что последняя операция могла завершиться неуспешно
  • Вариант 3. Отслеживание транзакции вручную

    1. Добавьте неотслеживающую таблицу в базу данных, используемую для наблюдения за состоянием транзакций.
    2. Вставка строки в таблицу в начале каждой транзакции.
    3. В случае сбоя соединения во время фиксации проверьте наличие соответствующей строки в базе данных.
      • Если строка имеется, продолжайте обычно, так как транзакция была успешно зафиксирована.
      • Если строка отсутствует, используйте стратегию выполнения, чтобы повторить текущую операцию.
    4. Если фиксация прошла успешно, удалите соответствующую строку, чтобы избежать роста таблицы.

Эта запись блога содержит пример кода для выполнения этой задачи на SQL Azure.