Как откатить несколько запросов на разных серверах баз данных в случае любой ошибки - PullRequest
1 голос
/ 09 сентября 2011

Я использую различные процедуры SQL в приложении.Первые процедуры вставляют несколько строк, затем некоторую обработку в коде C #, а затем 2-я процедура выполняет некоторое обновление, затем снова некоторая обработка кода, затем третья процедура удаляет некоторую запись и затем вставляет новую запись.Когда все выполнено на сервере 1, данные извлекаются с этого сервера и отправляются на сервер 2, где запись удаляется, и добавляется новая запись.Если есть ошибка на любом этапе на любом сервере в любой процедуре, я хочу откатить всю запись.Я не могу использовать начало транс, потому что обработка занимает много времени и не может заблокировать таблицу, так как другие пользователи также используют те же таблицы параллельно.Поэтому, пожалуйста, скажите мне, как я могу достичь этого, не блокируя таблицу для других пользователей.

Заранее спасибо.

Отредактировано (добавлен пример кода): я пытался определить объем транзакции, но получаю исключение, покаоткрытие соединения.Я настроил MS DTC, но, возможно, настроен неправильно.

" Доступ к сети для диспетчера распределенных транзакций (MSDTC) отключен. Пожалуйста, включите DTC для доступа к сети в конфигурации безопасности для MSDTC с использованием служб компонентовИнструмент администрирования . "

using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
    {


        try
        {
            dl.SetBookReadyToLive(13570, false);
            //SetBookReadyToLive
            dl.AddTestSubmiitedTitleID(23402);
            dl.AddBookAuthorAtLIve(13570, 1);
            ts.Complete();

        }
        catch (Exception ex)
        {
            Response.Write(ex.Message);
        }
    }

public void SetBookReadyToLive (длинный BookID, состояние bool) {try {if (dbConMeta.State! = ConnectionState.Open) dbConMeta.Open ();

          SqlCommand cmd = new SqlCommand("spSetBookReadyToLive", dbConMeta);
          cmd.CommandType = CommandType.StoredProcedure;
          cmd.Parameters.Clear();
          cmd.Parameters.Add("@BookID", BookID);
          cmd.Parameters.Add("@status", status);
          cmd.ExecuteNonQuery();
          if (dbConMeta.State == ConnectionState.Open)
              dbConMeta.Close();

      }
      catch
      {
          if (dbConMeta.State == ConnectionState.Open)
              dbConMeta.Close();

      }

  }

Я получаю исключение при открытии соединения метода>

Я использую SQL Server 2000, я установил конфигурацию MS DTC на компьютере, на котором установлен SQL Server, а также на моем ПК.откуда я запускаю кодНо все же исключение.

Пожалуйста, помогите мне настроить его

Ответы [ 2 ]

2 голосов
/ 12 сентября 2011

Вы можете использовать класс TransactionScope. В целом это работает хорошо, но в случае распределенных серверов SQL, как в вашем случае, требуется, чтобы MS DTC был включен на обоих серверах и правильно настроен (должна быть обеспечена безопасность для выполнения сетевых транзакций, распределенных и т. Д.)

здесь копия вставки из примера на MSDN, вы могли бы "почти" использовать его следующим образом ...:)

// Create the TransactionScope to execute the commands, guaranteeing
// that both commands can commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
    using (SqlConnection connection1 = new SqlConnection(connectString1))
    {
        // Opening the connection automatically enlists it in the 
        // TransactionScope as a lightweight transaction.
        connection1.Open();

        // Create the SqlCommand object and execute the first command.
        SqlCommand command1 = new SqlCommand(commandText1, connection1);
        returnValue = command1.ExecuteNonQuery();
        writer.WriteLine("Rows to be affected by command1: {0}", returnValue);

        // If you get here, this means that command1 succeeded. By nesting
        // the using block for connection2 inside that of connection1, you
        // conserve server and network resources as connection2 is opened
        // only when there is a chance that the transaction can commit.   
        using (SqlConnection connection2 = new SqlConnection(connectString2))
        {
            // The transaction is escalated to a full distributed
            // transaction when connection2 is opened.
            connection2.Open();

            // Execute the second command in the second database.
            returnValue = 0;
            SqlCommand command2 = new SqlCommand(commandText2, connection2);
            returnValue = command2.ExecuteNonQuery();
            writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
        }
    }

    // The Complete method commits the transaction. If an exception has been thrown,
    // Complete is not  called and the transaction is rolled back.
    scope.Complete();

}

источник: Класс TransactionScope

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

Примечание: Лично я не стал бы использовать этот, если бы в этом не было крайней необходимости, потому что всегда сложно настраивать DTC, а распределенные транзакции, как правило, медленнее, чем локальные, но в действительности зависят от вашего Логика BL / DAL.

0 голосов
/ 12 сентября 2011

Краткий ответ: Точно так же, как если бы вы делали это в MS SQL Management Studio.

  1. Вы открываете соединение с сервером.
  2. Открываете транзакцию для определенного сервера
  3. Вы запускаете запросы, связанные с этим сервером
  4. Вы убедитесь, что ваше соединение работает, пока вы ... [переходите к 1. для следующего сервера]

Если все ваши запросы сработали, подтвердите все ваши изменения.Иначе, откатите все ваши запросы.

Предупреждение. Первая таблица, скорее всего, будет заблокирована, пока вы не закончите со всеми своими серверами / запросами.Что вы можете сделать здесь, чтобы помочь этому: если вы получили много данных, вы можете перенести данные во временные таблицы на всех серверах перед выполнением шага № 2.Как только это будет сделано, вы откроете транзакцию, выполните свои быстрые действия, а затем подтвердите / отката как можно скорее.

Примечание.идея в части «предупреждение».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...