2012-04-13 11 views
9

Próbuję znaleźć różnicę między używaniem SqlBulkCopy z opcją kopiowania SqlBulkCopyOptions.UseInternalTransaction i bez niej, ale w mojej aplikacji testowej nie wykryłem żadnej różnicy. Jeśli BatchSize jest na przykład 0 i dodaję 100 rekordów (w DataTable), gdzie rekord 50 powoduje błąd podczas dodawania go do tabeli bazy danych, otrzymuję 0 rekordów w tabeli. Jeśli na przykład BatchSize jest ustawiona na 10, otrzymuję 40 rekordów (4 partie po 10 rekordów, piąta partia zawiera wadliwy rekord i powoduje przerwanie masowego kopiowania). Nie ma znaczenia, czy S qlBulkCopyOptions.UseInternalTransaction jest ustawiony czy nie, zawsze otrzymuję taki sam wynik. Wygląda na to, że partie są zawsze kopiowane w wewnętrznej transakcji.SqlBulkCopy: Jaka jest różnica między przekazywanie SqlBulkCopyOptions. UseInternalTransaction i nie przekazywanie go?

Jeśli jesteś zainteresowany moją aplikacją testową, to jest tutaj: SqlBulkCopy-Error-and-Transaction-Test.zip

moje pytania są następujące:

  1. Czy SqlBulkCopyOptions.UseInternalTransaction nieaktualne ponieważ SqlBulkCopy zawsze wykorzystuje transakcje wewnętrzne?
  2. Jeśli nie: jakie jest rzeczywiste znaczenie tej opcji? W jakich przypadkach miałoby to znaczenie?

nadzieję, że ktoś może wyjaśnić

Edit: Według odpowiedzi i komentarze Przypuszczam, że mój problem nie ist wystarczająco jasne. Znam dokumentację. Mówi, że "Domyślnie operacja kopiowania zbiorczego jest jego własną transakcją." i że każda partia używa swojej własnej transakcji, przekazując UseInternalTransaction. Ale jeśli to oznacza, że ​​domyślnie operacja kopiowania zbiorczego używa tylko jednej transakcji dla całej kopii zbiorczej (a nie jednej dla każdej partii), nie pobrałbym rekordów w bazie danych, jeśli ustawię rozmiar pliku BatchSize na określony rozmiar i partia, która znajduje się po pierwszy powoduje błąd. Gdyby użyć tylko jednej transakcji, wszystkie rekordy dodane do dziennika transakcji zostaną wycofane. Ale dostaję zapisy partii, które leżą przed wsadem zawierającym wadliwy zapis. Zgodnie z tym wydaje się, że domyślnie każda partia jest wykonywana w swojej własnej transakcji. Oznacza to, że nie ma znaczenia, czy przekażę UseInternalTransaction, czy też nie. Jeśli znajdę się na niewłaściwej ścieżce, naprawdę doceniłbym, gdyby ktoś mógł wyjaśnić.

Jeden fakt może być ważny: Używam SQL Server 2012. Może SQL Server 2008 zachowuje się inaczej. Sprawdzę to.

Edit: Dzięki odpowiedzi od usr Myślę, że znalazłem odpowiedź: I debugowania i wyprofilowany kawałek i okazało się, że prywatny _internalTransaction pole jest naprawdę nie jest ustawiona jeśli UseInternalTransaction nie jest zdefiniowana. SqlBulkCopy następnie nie używa własnej (wewnętrznej) transakcji. Ale profilowanie wskazuje, że SqlBulkCopy używa TDS (Tabular Data Stream) do kopiowania danych (bez względu na to, co jest BatchSize). Nie znalazłem wiele informacji o TDS specjalnie dla SQL Server, ale zakładam, że SQL Server wykonuje operacje masowego kopiowania TDS w wewnętrznej transakcji. Dlatego UseInternalTransaction wydaje się być zbędny dla SQL Server, ale po bezpiecznej stronie ustawiłbym go.

+0

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

+0

Dzięki Tim. Tak, dokumentacja mówi "Domyślnie operacja kopiowania zbiorczego jest jego własną transakcją". Nieco później mówi: "Możesz jawnie określić opcję UseInternalTransaction w konstruktorze klasy SqlBulkCopy, aby jawnie spowodować, że operacja kopiowania zbiorczego zostanie wykonana w ramach własnej transakcji, powodując, że każda partia operacji kopiowania zbiorczego zostanie wykonana w ramach oddzielnej transakcji". To jest mylące. A moja aplikacja testowa nie wykazuje żadnej różnicy! Zobacz mój komentarz do odpowiedzi od Ariona. Tylko jeśli przekażę własną transakcję, otrzymam 0 rekordów dodanych w przypadku błędu. Wypróbuj moją aplikację testową ... –

+0

Tim Schmelter: Link nie ma znaczenia. Nie wyjaśnia to, jak napisać ** pakiet ** na serwer bez transakcji. Jeśli rozumiem pytanie OP, to nie chodzi o to, jak sprawić, aby cała operacja kopiowania zbiorczego była transakcją. Potwierdzam odkrycie Jurgena. UseInternalTransaction nie jest w tym przypadku skuteczna. – JohnC

Odpowiedz

2

Jeśli ustawisz tę opcję, a następnie klasa SQLBulkCopy doda

_internalTransaction = _connection.BeginTransaction(); 

wokół każdej partii.

Jednak ta opcja nie ma praktycznego znaczenia dla SQL Server, ponieważ transakcje domyślnie działają w trybie automatycznego zatwierdzania.

Jedyną obserwowalną różnicą jest to, że sprawdza ona, czy nie próbowałaś przekazać transakcji zewnętrznej.

dodaje się uda i wycofać wszystkie partie

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(); 

Przechodząc SqlBulkCopyOptions.UseInternalTransaction nie powiedzie się z powodu błędu

nie musi określać SqlBulkCopyOption.UseInternalTransaction i zdać zewnętrznego transakcja w tym samym czasie.

Zastanawiałam się, czy to może mieć znaczenie, jeśli SET IMPLICIT_TRANSACTIONS ON; wcześniej uruchomić na połączenia, aby wyłączyć automatyczny tryb ale przeciążenie konstruktora SqlBulkCopy który zabierze obiekt połączenia zwraca popełnić „Unexpected istniejących transakcji.” błąd w obu przypadkach - i przeciążenie, które pobiera ciąg połączenia, tworzy właśnie nowe połączenie.

Powiązane problemy