2016-10-07 4 views
2

Я использую базу данных azure sql (v12) на vm. У меня есть два разных экземпляра баз данных - один для постановки и один для производства. Я пытаюсь захватить данные с этапа и вставить его в производство одним нажатием кнопки. Этот код работает «иногда», что означает случайным образом, что он будет успешным. В противном случае я получаю обратно ошибку:Azure - SqlBulkCopy исключение тайм-аута с истекшим сроком действия

BULK COPY Commit Тип Exception: {0} System.Data.SqlClient.SqlException BULK COPY Сообщение: {0} Время ожидания истекло. Период ожидания истекает до завершения операции или сервер не отвечает. Эта ошибка произошла при попытке подключения к адресату маршрутизации. Продолжительность, затрачиваемая при попытке подключения к исходному серверу, была - [Pre-Login] initialization = 1; квитирование = 17; [Login] initialization = 0; Аутентификация = 0; [Post-Login] complete = 0;

Вот код, который я использую для выполнения этой задачи, возможно, есть недостаток, который я не вижу. По дампу StringBuilder я вижу, что запрос SELECT работает, и запрос DELETE работает, но ошибка возникает, когда я пытаюсь скопировать данные с помощью SqlBulkCopy. Любая помощь будет принята с благодарностью. Я прошел через кучу документов MSDN уже без везения -> добавление более длинного CommandTimeouts, добавление более длинного BulkCopyTimeout и перенастройка портов на моем брандмауэре. Еще не повезло.

Ресурсы Я использовал: https://social.msdn.microsoft.com/Forums/en-US/1467d64f-69ae-4c1f-91a2-349fc5d514ae/sqlbulkcopy-fails-with-timeout-expired-error?forum=adodotnetdataproviders

https://azure.microsoft.com/nb-no/documentation/articles/sql-database-develop-direct-route-ports-adonet-v12/

Timeout expired with SqlBulkCopy

public static object SyncData() 
{ 
    StringBuilder sb = new StringBuilder(); 
    sb.AppendLine("Internal Connection..."); 
    string internalConnectionString = GetConnectionString("ConnectionString"); 
    using (SqlConnection internalConnection = new SqlConnection(internalConnectionString)) 
    { 
     internalConnection.Open();    
     SqlCommand selectCommand = internalConnection.CreateCommand(); 
     selectCommand.CommandTimeout = 180; 
     try 
     { 
      selectCommand.CommandText = "SELECT * FROM dbo.test"; 
      SqlDataReader reader = selectCommand.ExecuteReader(); 

      sb.AppendLine("External Connection..."); 
      string externalConnectionString = GetConnectionString("ExternalConnectionString"); 
      using (SqlConnection externalConnection = new SqlConnection(externalConnectionString)) 
      { 
       externalConnection.Open();    
       SqlCommand CRUDCommand = externalConnection.CreateCommand(); 
       CRUDCommand.CommandTimeout = 180; 
       SqlTransaction transaction = externalConnection.BeginTransaction("test"); 
       CRUDCommand.Connection = externalConnection; 
       CRUDCommand.Transaction = transaction; 
       try 
       { 
        CRUDCommand.CommandText = "DELETE FROM dbo.test"; 
        sb.AppendLine("DELETE: Number of rows affected = " + CRUDCommand.ExecuteNonQuery()); 
        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(externalConnection, SqlBulkCopyOptions.KeepIdentity, transaction)) 
        { 
         try 
         { 
          bulkCopy.DestinationTableName = "dbo.test"; 
          bulkCopy.BatchSize = 100; 
          bulkCopy.BulkCopyTimeout = 180; 
          bulkCopy.WriteToServer(reader); 

          sb.AppendLine("Table data copied successfully"); 

          transaction.Commit(); 
          sb.AppendLine("Transaction committed."); 
         } 
         catch (Exception ex) 
         { 
          sb.AppendLine("BULK COPY Commit Exception Type: {0}" + ex.GetType()); 
          sb.AppendLine(" BULK COPY Message: {0}" + ex.Message); 
          try 
          { 
           transaction.Rollback(); 
          } 
          catch (Exception ex2) 
          { 
           sb.AppendLine("Rollback Exception Type: {0}" + ex2.GetType()); 
           sb.AppendLine(" Message: {0}" + ex2.Message); 
          } 
         } 
         finally 
         { 
          reader.Close(); 
         } 
        } 
       } 
       catch (Exception ex) 
       { 
        sb.AppendLine("Commit Exception Type: {0}" + ex.GetType()); 
        sb.AppendLine(" Message: {0}" + ex.Message); 

        try 
        { 
         transaction.Rollback(); 
        } 
        catch (Exception ex2) 
        { 
         sb.AppendLine("Rollback Exception Type: {0}" + ex2.GetType()); 
         sb.AppendLine(" Message: {0}" + ex2.Message); 
        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      sb.AppendLine("Commit Exception Type: {0}" + ex.GetType()); 
      sb.AppendLine(" Message: {0}" + ex.Message); 
     } 
    } 
    return sb.ToString(); 
} 
+0

Оба сервера в одной виртуальной сети? Вы пытались поэкспериментировать с тайм-аутами и, возможно, увеличивать размер партии, поэтому не так много поездок в оба конца? У меня есть аналогичный процесс, хотя я использую Dapper, Reactive Extensions и Simple.Data для достижения того же. В моем случае мне просто нужно было поиграть с настройками, пока не найду лучшие результаты. Также у меня есть логика повтора, которая помогает, но нет серебряной пули ИМХО. – jcwrequests

+0

да обе базы данных находятся на одном и том же сервере. я пытался увеличить свои таймауты до 30 минут, но это просто заставляет их висеть в течение 30 минут ... Стол для копирования сейчас составляет всего 400 строк, поэтому изменение размера партии не повлияло на меня. – c22joe

+0

Является ли процесс запуском кода в той же виртуальной сети? – jcwrequests

ответ

1

При создании экземпляра SqlBulkCopy, вы передаете строку соединения externalConnectionString и, таким образом, открывая новое соединение. Это может вызвать проблему взаимоблокировки с обоими соединениями, пытающимися изменить одну и ту же таблицу.

Вы пытались передать существующее соединение externalConnection в конструктор SqlBulkCopy вместо строки соединения?

+0

Хорошо, я попробую это. – c22joe

+0

Ты так прав, когда я создал экземпляр SqlBulkCopy, я заблокировал таблицу из-за моего предыдущего запроса DELETE той же таблицы. Все, что мне нужно было сделать, это изменить конструктор на 'using (SqlBulkCopy bulkCopy = новый SqlBulkCopy (externalConnection, SqlBulkCopyOptions.KeepIdentity, транзакция)), и он отлично работал. Спасибо! – c22joe

Смежные вопросы