问题
Does nhibernate have some way of maintaining order of updates to avoid deadlocks across concurrent transactions?
For example if I have two transactions T1 and T2 executing concurrently. Let's say I'm updating 2 rows in a table called order on a field called cancelled.
T1
Update order set cancelled = 0 where order_id = 1
Update order set cancelled = 0 where order_id = 2
T2
Update order set cancelled = 0 where order_id = 2
Update order set cancelled = 0 where order_id = 1
Obviously the above will result in a deadlock if they both execute at or around the same time because T1 will be waiting to acquire a lock on order 2 and T2 will be waiting to acquire a lock on order 1.
My question is how do I ensure that the order of these updates are always the same? Is this simply handled by updating the entities in the same order in both transactions?
So if I do the following on the entities am I guaranteed the updates will occur in the right order?
Order order1 = session.Get<Order>(1);
Order order2 = session.Get<Order>(2);
using(ITransaction tran = session.StartTransaction())
{
order1.Cancelled = 0;
order2.Cancelled = 0;
tran.Commit();
}
In addition to this I wonder about updates across different tables. So if I were to update a table called order and also a table called order_line similar to the example above does nhibernate have some automagical way of doing it in the same order every time?
Edit
It appears the entity framework does support this natively as of v4. The below article explains this:
Ordering of operations
EF does not expose a way to control the ordering of operations during SaveChanges. EF v1 indeed had specific issues with high isolation levels (e.g. Serializable) which could produce deadlocks during SaveChanges. It is not a very well publicized feature, but in EF 4 we changed the update pipeline to use more deterministic ordering for uncorrelated CUD operations. This helps ensure that multiple instances of a program will use the same ordering when updating the same set of tables, which in turns helps reduce the possibility of a deadlock.Besides SaveChanges, if you need to have transactions with high isolation while executing queries, you can manually implement a similar approach: make sure your application always accesses the same pair of tables in the same order, e.g. use alphabetical order.
Above was taken from here
Apparently there is also a post in the nhusers group on this from January of 2013: https://groups.google.com/forum/#!searchin/nhusers/deadlock/nhusers/WVCEJfD3B_w/DGBhHta79cMJ
回答1:
I think I found my answer by digging through the nhibernate code. The answer is yes and no. NHibernate does have the ability to order the INSERT statements but you have to manually set this configuration in the config file via:
<property name="order_inserts">true</property>
One interesting thing to note here is that it will default to true if adonet.batch_size
is > 0. If this is not > 0 you need to manually set this.
Updates in NHibernate do NOT have this same functionality. The underlying classes support this but they do not have a way to set it from the config file and the default value (default boolean value in C#) is false. Should they ever expose this to the configuration the updates executed in a flush command or transaction would be ordered.
The way NHibernate orders the INSERTS is by class name then by primary key. Should they ever expose the update ordering it would work the same way. I hope someone finds this insightful because I sure did.
If anyone is interested the underlying class that supports this is Settings
. It's a property called:
public bool IsOrderUpdatesEnabled { get; internal set; }
来源:https://stackoverflow.com/questions/24175257/maintaining-order-of-updates-across-transactions-to-avoid-deadlocks