SqlCommand z transakcją zwraca "stare/niepoprawne" wartości

0

Hej.
Problem mam dość irytujący i od jakiegoś czasu mocno dokuczający, więc potrzebuję jakiegoś punktu zaczepienia, ze względu na wyczerpanie się moich pomysłów, co jest nie tak.

Przyjmijmy w uproszczeniu, że mój kod wygląda tak (baza MSSQL, .NET 4.0):

bool correct = false;
do
	{
	SqlTransaction transaction = null;
	try
	{
		// połącz z bazą:
		// (...)
		
		transaction = database.conn.BeginTransaction(IsolationLevel.Serializable);
		SqlCommand selectCmd = new SqlCommand();
		selectCmd.Connection = database.conn;
		selectCmd.CommandType = CommandType.Text;
		selectCmd.CommandText = @"SELECT TOP 1 id1, id2 FROM ids";
		selectCmd.Transaction = transaction;
		
		SqlDataAdapter da = new SqlDataAdapter();
		da.SelectCommand = selectCmd;
		DataTable dtIds = new DataTable();
		da.Fill(dtIds);
		
		int id1 = Int32.Parse(dtIds.Rows[0]["id1"].ToString());
		int id2 = Int32.Parse(dtIds.Rows[0]["id2"].ToString());

		SqlCommand sqlUpdtIds = new SqlCommand();
		sqlUpdtIds.Connection = database.conn;
		sqlUpdtIds.CommandType = CommandType.Text;
		sqlUpdtIds.CommandText = @"UPDATE ids SET id1 = id1 + 1, id2 = id2 + 1";
		sqlUpdtIds.Transaction = transaction;

		sqlUpdtIds.ExecuteNonQuery();
		
		// jakieś tam operacja korzystające z powyższych id'ków
		
		SqlBulkCopy bulkCopy = new SqlBulkCopy(database.conn, SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.FireTriggers, transaction);
		
		// jakieś tam mapowanie kolumn
		bulkCopy.DestinationTableName = "table1";
		bulkCopy.BatchSize = tableSize;
		bulkCopy.WriteToServer(dtTable1);
		
		transaction.Commit();
		
		correct = true;
	}
	catch (Exception ex)
	{
		if (transaction != null)
			transaction.Rollback();
		
		// loguj błąd i poczekaj chwilę
	}
} while (!correct);

Jak widać, najpierw robię selecta, żeby otrzymać id'y tabel, później update'a na tej tabelce z id'ami, później jakieś operacje z tym związane, a następnie zrzut danych do tabelki, która ma pobrane id'y jako PK.

Na bazie jest wykonywanych sporo operacji (raz krótkich, raz bardzo długich), z różnych źródeł, więc czasami się gdzieś jakiś długi lock zdarzy, a co za tym idzie pójdzie timeout na selectcie, albo insercie/updatcie.

Teraz najważniejsze dla mnie pytanie:
Dlaczego powyższy kod po złapaniu wyjątku i ponownej próbie zapisu danych do bazy (mimo tego, że select, update i bulkcopy odbywają się w obrębie 1 transakcji) pobiera stare lub w momencie zrzucenia przez SqlBulkCopy.WriteToServer() nieaktualne dane (jakiś inny proces uaktualnił już tabelkę z id'ami) i wyrzuca, że nie może dopisać do tej tabeli danych (ze względu na konflikt PK)?

Będę wdzięczny za każdą sensowną podpowiedź :)

0

zmień poziom izolacji transakcji na ReadCommitted i zobacz czy pomoże

1 użytkowników online, w tym zalogowanych: 0, gości: 1