Как я делаю вложенные транзакции в NHibernate?

Фокусник ловкость рук ! Тем, что можно думать, что Вы видите, можно тайно управлять или заменить.

18
задан Gavin 28 April 2010 в 09:07
поделиться

3 ответа

Эта реализация не поддерживает вложение, если вы хотите использовать вложение, используйте реализацию UnitOfWork Айенде . Другая проблема с реализацией, которую вы используете (по крайней мере, для веб-приложений), заключается в том, что она удерживает экземпляр ISession в статической переменной.

Я только что вчера переписал наш UnitOfWork по этим причинам, он изначально был основан на Габриэле.

Мы не используем UnitOfWork.Current.BeginTransaction (), мы используем UnitofWork.TransactionalFlush (), который создает отдельную транзакцию в самом конце, чтобы сбросить все изменения сразу.

using (var uow = UnitOfWork.Start())
{
     var entity = repository.Get(1);
     entity.Name = "Sneal";
     uow.TransactionalFlush();
}
1
ответ дан 30 November 2019 в 08:58
поделиться

Я уже некоторое время борюсь с этим. Я собираюсь сделать еще один взлом.

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

Поскольку я использую Rhino Commons , я собираюсь попробовать провести рефакторинг с использованием метода With.Transaction . По сути, это позволяет нам писать код, как если бы транзакции были вложенными, хотя на самом деле существует только одна.

Например:

private Project CreateProject(string name)
{
    var project = new Project(name);
    With.Transaction(delegate
    {
        UnitOfWork.CurrentSession.Save(project);
    });
    return project;
}

private Sample CreateSample(Project project, string code)
{
    var sample = new Sample(project, code);
    With.Transaction(delegate
    {
        UnitOfWork.CurrentSession.Save(sample);
    });
    return sample;
}

private void Test_NoNestedTransaction()
{
  var project = CreateProject("Project 1");
}

private void TestNestedTransaction()
{
  using (var tx = UnitOfWork.Current.BeginTransaction())
  {
      try
      {
          var project = CreateProject("Project 6");
          var sample = CreateSample(project, "SAMPLE006", true);
      }
      catch
      {
          tx.Rollback();
          throw;
      }
      tx.Commit();
  }
}

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

В Test_NestedTransaction () мы создаем и образец, и проект. Если что-то пойдет не так, мы хотим, чтобы оба были откатаны. На самом деле код в CreateSample и CreateProject будет работать так же, как если бы транзакций не было вообще; Это полностью внешняя транзакция, которая решает, откатить или зафиксировать, и делает это в зависимости от того, было ли выброшено исключение. На самом деле, поэтому я использую транзакцию, созданную вручную для внешней транзакции; так что у меня есть контроль над фиксацией или откатом, а не просто по умолчанию на on-exception-rollback-else-commit .

Вы могли бы добиться того же и без Rhino.Commons, добавив в свой код множество подобных вещей:

if (!UnitOfWork.Current.IsInActiveTransaction)
{
  tx = UnitOfWork.Current.BeginTransaction();
}

_auditRepository.SaveNew(auditEvent);
if (tx != null)
{
  tx.Commit();
}

... и так далее. Но With.Transaction , несмотря на всю громоздкость необходимости создавать анонимные делегаты, делает это довольно удобно.

Преимущество этого подхода перед использованием TransactionScope (помимо зависимости от MSDTC) состоит в том, что при окончательной фиксации внешней транзакции должен быть только один сброс в базу данных, независимо от того, как многие методы были вызваны промежуточными. Другими словами, нам не нужно записывать незафиксированные данные в базу данных по ходу работы, мы всегда просто записываем их в локальный кеш NHibernate.

Короче говоря, это решение не предлагает окончательного контроля над вашими транзакциями, потому что оно никогда не использует более одной транзакции. Думаю, я могу согласиться с этим, поскольку вложенные транзакции никоим образом не поддерживаются повсеместно в каждой СУБД. Но теперь, возможно, я смогу хотя бы написать код, не беспокоясь о том, находимся мы уже в транзакции или нет.

2
ответ дан 30 November 2019 в 08:58
поделиться

Сеансы NHibernate не поддерживают вложенные транзакции.

Следующий тест всегда выполняется в версии 2.1.2:

var session = sessionFactory.Open();
var tx1 = session.BeginTransaction();
var tx2  = session.BeginTransaction();
Assert.AreEqual(tx1, tx2);

Вам необходимо заключить его в TransactionScope для поддержки вложенных транзакций.

MSDTC должен быть включен, иначе вы получите сообщение об ошибке:

{"Сетевой доступ для диспетчера распределенных транзакций (MSDTC) отключен.Включите DTC для доступа к сети в конфигурации безопасности для MSDTC с помощью инструмента администрирования служб компонентов. "}

14
ответ дан 30 November 2019 в 08:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: