2012-04-13 2 views
9

Я пытаюсь найти разницу между использованием SqlBulkCopy с опцией копирования SqlBulkCopyOptions.UseInternalTransaction и без нее, но в моем тестовом приложении я не обнаруживаю никакой разницы. Если BatchSize является, например, 0, и я добавляю 100 записей (в DataTable), где номер записи 50 вызывает ошибку при добавлении ее в таблицу базы данных, я получаю 0 записей в таблице. Если BatchSize установлено, например, 10, я получаю 40 записей (4 партии из 10 записей, пятая партия содержит ошибочную запись и приводит к прерыванию массовой копии). Не имеет значения, установлен ли S qlBulkCopyOptions.UseInternalTransaction или нет, я всегда получаю тот же результат. Кажется, что партии всегда копируются во внутренней транзакции.SqlBulkCopy: В чем разница между передачей SqlBulkCopyOptions.UseInternalTransaction и не передачей его?

Если вы заинтересованы в моем тестовом приложении, здесь: SqlBulkCopy-Error-and-Transaction-Test.zip

Мои вопросы:

  1. Является SqlBulkCopyOptions.UseInternalTransaction устаревшим, поскольку SqlBulkCopy всегда использует внутренние транзакции?
  2. Если нет: каково фактическое значение этой опции? В каких случаях это имело бы значение?

Надежда кто-то может прояснить

Edit: Согласно ответу и замечания я предполагаю, что моя проблема не исть достаточно ясно. Я знаю документацию. В нем говорится, что «По умолчанию операция массового копирования - это его собственная транзакция». и что каждая партия использует свою собственную транзакцию при прохождении UseInternalTransaction. Но если это означает, что по умолчанию операция массового копирования использует только одну транзакцию для всей массовой копии (а не для каждой партии), я бы не получил записи в базе данных, если бы я установил BatchSize в определенный размер и пакет, который находится после первая вызывает ошибку. Если будет использоваться только одна транзакция, все записи, добавленные в журнал транзакций, будут отброшены назад. Но я получаю записи партий, которые лежат перед партией, включающей неисправную запись. В соответствии с этим кажется, что по умолчанию каждая партия выполняется в собственной транзакции. Это означает, что не имеет значения, пропускаю ли я UseInternalTransaction или нет. Если я ошибаюсь, я бы очень признателен, если бы кто-то мог прояснить ситуацию.

Один факт может быть важен: я использую SQL Server 2012. Может быть, SQL Server 2008 ведет себя по-другому. Я проверю это.

Edit: Благодаря ответ от USR Я думаю, что я нашел ответ: я отлажена и профилированную немного, и обнаружила, что частное поле _internalTransaction действительно не устанавливается, если UseInternalTransaction не определен. Затем SqlBulkCopy не использует собственную (внутреннюю) транзакцию. Но профилирование показало, что SqlBulkCopy использует TDS (табличный поток данных) для копирования данных (независимо от того, что такое BatchSize). Я не нашел много информации о TDS, особенно для SQL Server, но я предполагаю, что SQL Server выполняет операции массового копирования TDS во внутренней транзакции. Поэтому UseInternalTransaction кажется излишним для SQL Server, но, чтобы быть в безопасности, я бы установил его.

+0

http://msdn.microsoft.com/en-us/library/tchktcdk%28v=vs.80%29.aspx –

+0

Спасибо Тим. Да, в документации говорится: «По умолчанию операция массового копирования - это собственная транзакция». Немного позже он говорит: «Вы можете явно указать параметр UseInternalTransaction в конструкторе класса SqlBulkCopy, чтобы явно вызвать операцию массовой копии в своей собственной транзакции, в результате чего каждая партия операции массовой копии выполнялась в рамках отдельной транзакции». Это смущает. И мое тестовое приложение не показывает никакой разницы! См. Мой комментарий к ответу от Ариона. Только если я передаю собственную транзакцию, я получаю 0 записей, добавленных в случае ошибки. Попробуйте мое тестовое приложение ... –

+0

Тим Шмельтер: Ссылка не имеет значения. Он не уточняет вопрос о том, как писать ** пакет ** на сервер без транзакции. Если я понимаю вопрос ОФ, речь идет не о том, как сделать всю операцию массовой копии транзакцией. Я подтверждаю нахождение Юргена. UseInternalTransaction не эффективен в этом случае. – JohnC

ответ

2

Если установить этот параметр, то класс SqlBulkCopy добавит

_internalTransaction = _connection.BeginTransaction(); 

вокруг каждой партии.

Но этот вариант не имеет практической разницы с SQL Server, поскольку транзакции по умолчанию работают в режиме автоматической фиксации в любом случае.

Единственная наблюдаемая разница заключается в том, что она выполняет проверку, что вы также не пытались передать внешнюю транзакцию.

Следующие преуспеют и откатить все партии

var transaction = sourceConnection.BeginTransaction();    
using (SqlBulkCopy bulkCopy = 
    new SqlBulkCopy(sourceConnection, SqlBulkCopyOptions.Default, transaction)) 

{ 
    bulkCopy.BatchSize = 50; 

    bulkCopy.DestinationTableName = "dbo.foobar"; 
     bulkCopy.WriteToServer(dt); 
} 

transaction.Rollback(); 

Передачи SqlBulkCopyOptions.UseInternalTransaction завершается с ошибкой

не должен указывать SqlBulkCopyOption.UseInternalTransaction и сдать внешнюю сделку одновременно.

Интересно, если это может сделать разницу, если SET IMPLICIT_TRANSACTIONS ON; ранее была запущена на связи, чтобы отключить автоматический режим, но перегрузку SqlBulkCopy конструктор, который принимает объект соединения возвращает совершить «Неожиданный существующую сделку.» ошибка в обоих случаях - и перегрузка, которая принимает строку соединения, просто создает новое соединение.

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