Подтвердить что ты не робот

С# управление транзакцией через несколько баз данных

Скажем, у меня есть приложение Windows Form, которое связано с базами данных n, при одновременном открытии соединений n.

То, что я ищу, - это сделать транзакцию со всеми этими базами данных за один раз.

Например, если у меня должно быть 2 подключения к базе данных:

using (ITransaction tx1 = session1.OpenTransaction())
{
    using (ITransaction tx2 = session2.OpenTransaction())
    {
        // Do the query thingy here
    }
}

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

Я хотел бы зациклить весь зарегистрированный сеанс и завершить его в службе, возможно, примерно так:

class TransactionManager
{
    private ISession[] _sessions;

    public TransactionManager(string[] connectionStrings)
    {
        // Initialize the sessions here
    }

    public function DoTransaction(string query)
    {
        foreach (ISession session in _sessions)
        {
            // What to do here? Using? Try-catch?
        }
    }
}

Если бы я использовал использование в цикле foreach, это означало бы, что если соединение A успешно, но соединение B не было, тогда откатывается только соединение B.

4b9b3361

Ответ 1

Кажется, вы можете повторно изобрести TransactionScope. Выполнение всего этого в рамках единицы работы прост *:

  using (TransactionScope scope = new TransactionScope())
  {
     ... Do Stuff with Connection 1 using SqlDataReader
     ... Do Stuff with Connection 2 using Entity Framework
     ... Do Stuff with Connection 3 on another Oracle Database
     ... And for good measure do some stuff in MSMQ or other DTC resource
     scope.Complete(); // If you are happy
  }

Stuff не обязательно должен быть встроенным - он может быть в другом классе или другой сборке. Нет необходимости явно регистрировать подключения к базе данных или очереди с помощью TransactionScope - все происходит automagically, при условии, что ресурсы, которые вы используете, могут записаться в окружающая транзакция.

Теперь небольшая печать:

  • * При одновременном использовании нескольких соединений с базой данных или разных цепочек соединений или нескольких технологий это потребует 2-фазный фиксатор и перейдем к транзакции DTC, чтобы обеспечить ACID через ресурсы. Сам DTC имеет намного более мелкий шрифт и предлагает гораздо больше проблемы в корпоративной сети, например , кластеризация, настройка безопасности и ошибки.
  • Однако при использовании транзакций Lightweight на сервере MS Sql, если вы можете сохранить все свои подключения с использованием одной и той же базы данных и того же настройки строки подключения и закрыть каждое соединение перед открытием следующий, то вы можете избежать DTC.

  • Поддержание транзакции по нескольким ресурсам ACID будет неизменно поддерживать блокировки этих ресурсов до тех пор, пока транзакция не будет завершена или не откат. Это часто не способствует добрососедству на предприятии большого объема, поэтому обязательно рассмотрите последствия блокировки.

  • Если Stuff выполняется через несколько потоков, вам нужно будет вставить DependentTransaction

  • Последнее, что стоит упомянуть, это уровень изоляции по умолчанию с TransactionScope - это Serializable, который подвержен взаимоблокировкам. В большинстве некритических сценариев вы, вероятно, сможете отказаться от этого Read Committed.

Ответ 2

используйте TransactionScope, он позаботится о том, чтобы выполнить или отменить все включенные транзакции:

using (var ts = new TransactionScope())
{
   ... // your old code

   ts.Complete()
}