Ich erhalte eine MSDTC-Ausnahme in einer Transaktion in einer C#-Anwendung. Die Funktionalität besteht darin, ein Lakh (hunderttausend) Zipcode-Datensätze in Datenbanktabellen hochzuladen, nachdem sie aus einer CSV-Datei gelesen wurden. Dieser Vorgang wird in etwa 20 Batch-Datenbankoperationen durchgeführt (jeder Batch enthält 5000 Datensätze). Die Funktion funktioniert gut, wenn ich keine Transaktion verwende.
Das Interessante daran ist, dass andere Funktionen, die Transaktionen verwenden, in der Lage sind, ihre Transaktionen abzuschließen. Dies führt mich zu der Annahme, dass die Ausnahmemeldung irreführend ist.
Haben Sie eine Idee, woran das liegen könnte?
Eine Ausnahme: "Der Netzwerkzugriff für Distributed Transaction Manager (MSDTC) wurde deaktiviert. Bitte aktivieren Sie DTC für den Netzwerkzugriff in der Sicherheitskonfiguration für MSDTC mit dem Component Services Administrative Tool."
Quelle: System.Transaktionen
Innere Ausnahme: "Der Transaktionsmanager hat seine Unterstützung für Remote-/Netzwerktransaktionen deaktiviert. (Ausnahme von HRESULT: 0x8004D024)"
Hinweis: Innerhalb der Transaktion gibt es eine for-Schleife. Verursacht sie ein Problem?
Die eigentliche Anforderung lautet: Es gibt einige bestehende Postleitzahlen in der Postleitzahlentabelle. Jeden Monat lädt der Administrator eine neue csv-Datei mit Postleitzahlen hoch. Die neuen Einträge aus der csv-Datei werden eingefügt. Postleitzahlen, die in der csv-Datei nicht vorhanden sind (aber in der Datenbank vorhanden sind), gelten als nicht mehr verfügbar und müssen gelöscht werden. Die Liste der gelöschten Postleitzahlen muss an die Benutzeroberfläche zurückgegeben werden. Die neu hinzugefügten Postleitzahlen müssen ebenfalls zurückgegeben werden.
private void ProcessZipCodes(StringBuilder dataStringToProcess, int UserID)
{
int CountOfUnchangedZipCode = 0;
string strRetiredZipCode = "";
string strNewZipCode = "";
dataStringToProcess.Remove(dataStringToProcess.Length - 1, 1);
if (dataStringToProcess.Length > 0)
{
List<string> batchDataStringList = GetDataStringInBatches(dataStringToProcess);
//TimeSpan.FromMinutes(0) - to make transaction scope as infinite.
using (TransactionScope transaction = TransactionScopeFactory.GetTransactionScope(TimeSpan.FromMinutes(0)))
{
foreach (string dataString in batchDataStringList)
{
PerformDatabaseOperation(dataString, UserID);
}
transaction.Complete();
}
}
}
private List<string> GetDataStringInBatches(StringBuilder dataStringToProcess)
{
List<string> batchDataStringList = new List<string>();
int loopCounter = 0;
string currentBatchString = string.Empty;
int numberOfRecordsinBacth = 5000;
int sizeOfTheBatch = 0;
List<string> individualEntriesList = new List<string>();
string dataString = string.Empty;
if (dataStringToProcess != null)
{
dataString = dataStringToProcess.ToString();
}
individualEntriesList.AddRange(dataString.Split(new char[] { '|' }));
for (loopCounter = 0; loopCounter < individualEntriesList.Count; loopCounter++)
{
if (String.IsNullOrEmpty(currentBatchString))
{
currentBatchString = System.Convert.ToString(individualEntriesList[loopCounter]);
}
else
{
currentBatchString = currentBatchString+"|"+System.Convert.ToString(individualEntriesList[loopCounter]);
}
sizeOfTheBatch = sizeOfTheBatch + 1;
if (sizeOfTheBatch == numberOfRecordsinBacth)
{
batchDataStringList.Add(currentBatchString);
sizeOfTheBatch = 0;
currentBatchString = String.Empty;
}
}
return batchDataStringList;
}
private void PerformDatabaseOperation(string dataStringToProcess, int UserID)
{
SqlConnection mySqlConnection = new SqlConnection("data source=myServer;initial catalog=myDB; Integrated Security=SSPI; Connection Timeout=0");
SqlCommand mySqlCommand = new SqlCommand("aspInsertUSAZipCode", mySqlConnection);
mySqlCommand.CommandType = CommandType.StoredProcedure;
mySqlCommand.Parameters.Add("@DataRows", dataStringToProcess.ToString());
mySqlCommand.Parameters.Add("@currDate", DateTime.Now);
mySqlCommand.Parameters.Add("@userID", UserID);
mySqlCommand.Parameters.Add("@CountOfUnchangedZipCode", 1000);
mySqlCommand.CommandTimeout = 0;
mySqlConnection.Open();
int numberOfRows = mySqlCommand.ExecuteNonQuery();
}
Dev Env: Visuelles Studium 2005
Rahmenwerk: .Net 3.0
DB: SQL Server 2005
Wenn ich die Abfrage SELECT [Size],Max_Size,Data_Space_Id,[File_Id],Type_Desc,[Name] FROM MyDB.sys.database_files WHERE data_space_id = 0 ausführe, wird die Größe (des Protokolls) auf 128
UPDATE Wir haben drei verschiedene Datenbanken in unserer Anwendung verwendet. Eine für Daten, eine für den Verlauf und eine für die Protokollierung. Wenn ich enlist = false in den obigen Connectionstring einfüge, funktioniert es vorerst. Aber es ist in meiner Entwicklungsumgebung. Ich bin skeptisch, ob es auch in der Produktion funktionieren wird. Hat jemand eine Idee zu möglichen Risiken?
Danke
Lijo