Reputation: 229
I have multiple console applications but they would be reading and inserting updating same sql table. I used transactionscope but I am getting this error "Transaction (Process ID) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction."
I get an exception in my catch block. How can I avoid this? I know what the problem is but I am not sure what should be the possible solution. I see a lot questions being asked on different forums but none of them really helped me.
Is everything good in my code?
bool isMaster = false;
tourneyInstanceTrackerId = 0;
using (JG_RummyEntities dbContext = new JG_RummyEntities())
{
try
{
using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required,new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
{
bool isAnyMaster = dbContext.TourneyInstanceTrackers.Any(t => t.IsMaster & t.TournamentId == tournamentId);
TourneyInstanceTracker tourneyInstanceTracker = new TourneyInstanceTracker
{
TournamentId = tournamentId,
IsMaster = !isAnyMaster,
CreateDate = DateTime.Now
};
dbContext.AddToTourneyInstanceTrackers(tourneyInstanceTracker);
dbContext.SaveChanges();
var result = dbContext.TourneyInstanceTrackers.Where(t => t.TournamentId == tournamentId)
.OrderByDescending(t => t.CreateDate)
.Select(t => new { t.IsMaster, t.Id })
.FirstOrDefault();
if (result != null)
{
isMaster = result.IsMaster;
tourneyInstanceTrackerId = result.Id;
}
transaction.Complete();
}
}
catch (Exception ex)
{
Logger.Log("Got exception in SetTournamentInTourneyInstanceTracker : " + ex.Message + ", " + ex.StackTrace + ", "+ tournamentId);
}
}
Upvotes: 0
Views: 195
Reputation: 127603
IsolationLevel.RepeatableRead
acts like a ReaderWriterLockSlim
, many threads can read a record at the same time but as soon as one wants to write you must wait for all readers to finish then take a exclusive lock on the object till you finish writing.
So imagine you have a program, it reads object "A" waits a bit then writes object "A". Now lets look at what happens when two copies of the program runs.
Program 1 Program 2 --------- --------- Begin Trans Not Started Read A Begin Trans Wait Read A Try Write A Wait Try Write A Try Write A Try Write A Try Write A Try Write A Try Write A
You can see Program 1 is waiting for Program 2 to release its read lock, however Program 2 can't release its read lock until Program 1 releases its read lock. This situation where the two are waiting for the other to finish is called a deadlock.
The are two ways you get around this, one you could use the more restrictive IsolationLevel.Serializable
, this blocks other readers until the transaction finishes.
Program 1 Program 2 --------- --------- Begin Trans Not Started Read A Begin Trans Wait Try Read A Write A Try Read A End Trans Read A Wait Write A End Trans
The other is you follow the exception's advice, on the block of code that caught the exception you re-run the function again until it gets through without another copy of the program blocking it.
Upvotes: 2