tags:

views:

937

answers:

5

Do you know of any ORM tool that offers deadlock recovery? I know deadlocks are a bad thing but sometimes any system will suffer from it given the right amount of load. In Sql Server, the deadlock message says "Rerun the transaction" so I would suspect that rerunning a deadlock statement is a desirable feature on ORM's.

+2  A: 

I don't know of any special ORM tool support for automatically rerunning transactions that failed because of deadlocks. However I don't think that a ORM makes dealing with locking/deadlocking issues very different. Firstly, you should analyze the root cause for your deadlocks, then redesign your transactions and queries in a way that deadlocks are avoided or at least reduced. There are lots of options for improvement, like choosing the right isolation level for (parts) of your transactions, using lock hints etc. This depends much more on your database system then on your ORM. Of course it helps if your ORM allows you to use stored procedures for some fine-tuned command etc.

If this doesn't help to avoid deadlocks completely, or you don't have the time to implement and test the real fix now, of course you could simply place a try/catch around your save/commit/persist or whatever call, check catched exceptions if they indicate that the failed transaction is a "deadlock victim", and then simply recall save/commit/persist after a few seconds sleeping. Waiting a few seconds is a good idea since deadlocks are often an indication that there is a temporary peak of transactions competing for the same resources, and rerunning the same transaction quickly again and again would probably make things even worse.

For the same reason you probably would wont to make sure that you only try once to rerun the same transaction.

In a real world scenario we once implemented this kind of workaround, and about 80% of the "deadlock victims" succeeded on the second go. But I strongly recommend to digg deeper to fix the actual reason for the deadlocking, because these problems usually increase exponentially with the number of users. Hope that helps.

markus
Good points, thank you. However - if we know that deadlocks happen and there are strategies for handling them (at least with Sql Server), why not put those in the DAL? Shouldn't this be desirable in an ORM?
Otávio Décio
I think it's still a workaround, and having first-class support for such a workaround would encourage people to stay with a pseudo solution instead of solving the actual issue.
markus
A: 

Deadlocks are to be expected, and SQL Server seems to be worse off in this front than other database servers. First, you should try to minimize your deadlocks. Try using the SQL Server Profiler to figure out why its happening and what you can do about it. Next, configure your ORM to not read after making an update in the same transaction, if possible. Finally, after you've done that, if you happen to use Spring and Hibernate together, you can put in an interceptor to watch for this situation. Extend MethodInterceptor and place it in your Spring bean under interceptorNames. When the interceptor is run, use invocation.proceed() to execute the transaction. Catch any exceptions, and define a number of times you want to retry.

John Ellinwood
Do you know if Hibernate is capable of keeping track of the statements in a transaction and re-run all of them in case of a deadlock? Would such feature be desirable in a ORM?
Otávio Décio
"SQL Server seems to be worse off in this front than other database servers" - completely untrue. Perhaps one of the reasons someone might think this, is that it is so easy to start using SQL Server, it is also easy to make mistakes.
Mitch Wheat
I actually think SQL does a pretty darn good job considering some of the horror database schemas I've seen over the years.
RobS
A: 

One system I worked on was based on “commands” that were then committed to the database when the user pressed save, it worked like this:

While(true)
   start a database transaction
   Foreach command to process
      read data the command need into objects
      update the object by calling the command.run method
   EndForeach
   Save the objects to the database
   If not deadlock
     commit the database transaction
    we are done
   Else 
     abort the database transaction
    log deadlock and try again
   EndIf
EndWhile

You may be able to do something like with any ORM; we used an in house data access system, as ORM were too new at the time.

We run the commands outside of a transaction while the user was interacting with the system. Then rerun them as above (when you use did a "save") to cope with changes other people have made. As we already had a good ideal of the rows the command would change, we could even use locking hints or “select for update” to take out all the write locks we needed at the start of the transaction. (We shorted the set of rows to be updated to reduce the number of deadlocks even more)

Ian Ringrose
Thank you. So you would think as acceptable for an ORM to offer such feature, even though some other respondents are against the notion because it might lead to carelessness from developers?
Otávio Décio
I think it has to be built on top of the ORM, as not all applications make use of commands. An ORM does not know how to rerun your C# code after all.
Ian Ringrose
It might know if for example when you start a transaction you collect each incoming statement as a unit of work and replay them in case of a failure such as deadlock.
Otávio Décio
The problem is that until we get transactional memory, the “unit of work” cannot abort the changes that were done to in memory objects that are not under the ORM control. Therefore I don’t see how a *general purpose* ORM and sort out deadlock without a lot of work from the application.
Ian Ringrose
while(true) is a bit harsh. Maybe try at most 3 or 5 times.
cherouvim
@cherouvim, a Thread.Sleep() with a "backout" timeout that is increase each time round the loop would also be helpful. However deadlocks are not common, if there are many deadlocks then a different database design, or update code is needed anyway.
Ian Ringrose
A: 

An o/r mapper can't detect this, as the deadlock is always occuring inside the DBMS, which could be caused by locks set by other threads or other apps even.

To be sure a piece of code doesn't create a deadlock, always use these rules: - do fetching outside the transaction. So first fetch, then perform processing then perform DML statements like insert, delete and update - every action inside a method or series of methods which contain / work with a transaction have to use the same connection to the database. This is required because for example write locks are ignored by statements executed over the same connection (as that same connection set the locks ;)).

Often, deadlocks occur because either code fetches data inside a transaction which causes a NEW connection to be opened (which has to wait for locks) or uses different connections for the statements in a transaction.

Frans Bouma
My purpose was somewhat less ambitious than a total assurance that deadlocks would be avoided or handled in all situations. The thing is, I saw cases where deadlocks occur due to load and retrying the statements is the right thing to do (mainly SQL server behaves that way).
Otávio Décio
Well, the things you should do are: 1) make sure every operation in a thread after a transaction is started is done with the same connection and 2) if an exception occurs, you should retry every operation as the complete transaction failed and of course 3) fetch outside the transaction!
Frans Bouma
In a great deal of cases, excessive locking or deadlocking can be alleviated or eliminated by creating the 'right' indexes for your query workload.
Mitch Wheat
true, indexes are also a way to avoid deadlocks through table-scans, though fetches outside transactions already solves it too.
Frans Bouma
Also consider what kind of transaction isolation level you require
RobS
A: 

I had a quick look (no doubt you have too) and couldn't find anything suggesting that hibernate at least offers this. This is probably because ORMs consider this outside of the scope of the problem they are trying to solve.

If you are having issues with deadlocks certainly follow some of the suggestions posted here to try and resolve them. After that you just need to make sure all your database access code gets wrapped with something which can detect a deadlock and retry the transaction.

Robin