Transaktions-deadlocks, wie design richtig?
Also arbeite ich an diesem Projekt von Entity Framework, die verwendet werden können als eine Art DAL und beim ausführen von stress-tests (beginnend ein paar updates auf Entitäten, die durch Gewinde()'s) und ich bekomme diese:
_innerException = {"Transaktion (Prozess-ID 94) befand sich auf sperren von Ressourcen mit einem anderen Prozess und wurde als Deadlockopfer ausgewählt. Wiederholung der Transaktion."}
Hier einige Beispiel, wie ich umgesetzt habe meine Klassen " Methoden:
public class OrderController
{
public Order Select(long orderID)
{
using (var ctx = new BackEndEntities())
{
try
{
var res = from n in ctx.Orders
.Include("OrderedServices.Professional")
.Include("Agency")
.Include("Agent")
where n.OrderID == orderID
select n;
return res.FirstOrDefault();
}
catch (Exception ex)
{
throw ex;
}
}
}
public bool Update(Order order)
{
using (var ctx = new BackEndEntities())
{
try
{
order.ModificationDate = DateTime.Now;
ctx.Orders.Attach(order);
ctx.SaveChanges();
return true;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
und:
public class AgentController
{
public Agent Select(long agentID)
{
using (var ctx = new BackEndEntities())
{
try
{
var res = from n in ctx.Agents.Include("Orders")
where n.AgentID == agentID
select n;
return res.FirstOrDefault();
}
catch (Exception ex)
{
throw ex;
}
}
}
public bool Update(Agent agent)
{
using (var ctx = new BackEndEntities())
{
try
{
agent.ModificationDate = DateTime.Now;
ctx.Agents.Attach(agent);
ctx.ObjectStateManager.ChangeObjectState(agent, System.Data.EntityState.Modified);
ctx.SaveChanges();
return true;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
Offensichtlich, den code hier wahrscheinlich könnte besser sein, aber ich bin eher ein EF-Neuling. Aber ich denke, mein problem ist eher ein design problem mit Kontext.
Ich erinnere mich, jemanden hier zu erwähnen, dass, wenn mein Rahmen ist NICHT freigegeben, ich kann nicht laufen in diesen deadlock-Probleme.
Scheint dies nicht 'shared', um mich, wie ich mit neuen BackEndEntities() in jeder Methode, also, was muss ich ändern, um es robuster ist ?
Dieser DAL wird in einem web-Dienst im internet verfügbar gemacht (nach code-review Gang), also habe ich keine Kontrolle darüber, wie viel es werde betont werden und viele verschiedene Instanzen aktualisieren möchten, auf die gleiche Entität.
Dank!
- Sie sollten einen gemeinsamen Kontext per HTTP-Anfrage-aus verschiedenen Gründen. Nicht länger, selten kürzer.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Deadlock-Freiheit ist ein ziemlich schwieriges problem in ein großes system. Es hat nichts zu tun mit EF von selbst.
Verkürzung der Lebensdauer Ihrer Transaktionen deadlocks reduziert, aber es stellt Daten-Inkonsistenzen. In jenen Orten, wo Sie waren Deadlocks zuvor sind Sie jetzt vernichten von Daten (ohne Benachrichtigung).
Wählen Sie also Ihrem Kontext Leben und Ihre Transaktion Lebensdauer gemäß den logischen Transaktion, nicht nach physikalischen überlegungen.
Aktivieren der snapshot-isolation. Dies dauert Lesen von Transaktionen völlig aus der Gleichung heraus.
Für das schreiben von Transaktionen, die Sie brauchen, um zu finden, eine Sperre bestellen. Oft ist es der einfachste Weg zu sperren pessimistisch und auf einem höheren Niveau. Beispiel: Sind Sie immer ändern von Daten in den Kontext eines Kunden? Nehmen Sie eine update-Sperre auf, die Kunden als erste Anweisung der Transaktionen. Bietet insgesamt deadlock-Freiheit durch serialisieren der Zugang zu diesem Kunden an.
Den Grund für die Justizgebäude von deadlocks ist nicht dein code, sondern durch EF wird mit SERIALIZABLE für Standard-TransactionScope-isolation-level.
SERIALISIERBAR ist die eingeschränkte sperren möglich, dies bedeutet, dass Sie standardmäßig die Entscheidung in den meisten restriktive Isolationsstufe, und Sie können erwarten, eine Menge von sperren!
Die Lösung ist, geben Sie eine andere TransactionScope-je nach Aktion, die Sie ausführen möchten. Sie können umgeben Sie Ihre EF-Aktionen mit so etwas wie dies:
Lesen Sie mehr zu diesem Thema:
http://blogs.msdn.com/b/diego/archive/2012/04/01/tips-to-avoid-deadlocks-in-entity-framework-applications.aspx
http://blogs.u2u.be/diederik/post/2010/06/29/Transactions-and-Connections-in-Entity-Framework-40.aspx
http://blog.aggregatedintelligence.com/2012/04/sql-server-transaction-isolation-and.html
https://serverfault.com/questions/319373/sql-deadlocking-and-timing-out-almost-constantly
Kontext ist es, was Einheit, seine Fähigkeit zu sprechen auf die Datenbank, ohne einen Kontext gibt es kein Konzept von dem, was geht, wo. Dreht ein Zusammenhang, daher ist eine große Sache, und es nimmt eine Menge von Ressourcen, einschließlich der externen Ressourcen wie die Datenbank. Ich glaube, dein problem IST der 'neue' Befehl, da hätten Sie mehrere threads, die versuchen sich zu drehen und greifen auf die gleiche Datenbank-Ressource, die auf jeden Fall würde deadlock.
Ihrem code, wie du gepostet hast scheint es sich um ein anti-pattern. So wie es aussieht, haben Sie Ihre Entität Kontext dreht und geht out of scope, relativ schnell, während Ihre CRUD-repository-Objekte zu sein scheinen persistierenden für eine viel längere Zeit.
Den Weg, die Unternehmen, die ich umgesetzt haben Entität für traditionell haben es geschafft genau den entgegengesetzten Weg - der Rahmen ist geschaffen, und wird so lange aufbewahrt, wie die Versammlung hat die Notwendigkeit von Datenbank-und repository-CRUD-Objekte erstellt werden und sterben in Mikrosekunden.
Kann ich nicht sagen, Woher Sie Ihre Behauptung der Kontext nicht freigegeben aus, also ich weiß nicht, welchen Umständen das gesagt wurde unter, aber es ist absolut wahr, dass Sie sollten nicht den Kontext über Assemblys. Bei der gleichen Versammlung ich sehe keinen Grund, warum Sie nicht mit, wie viele Ressourcen es braucht, um start-up-Kontext, und wie lange es dauert, dies zu tun. Der Entity-Kontext ist ziemlich schwer, und wenn Sie waren, um Ihren aktuellen code zu arbeiten, indem Sie die single-Thread-ich vermute, Sie würden sehen, einige absolut grauenhafte performance.
Also, was ich empfehlen würde, stattdessen ist die Umgestaltung dieses so haben Sie
Create(BackEndEntites context)
undUpdate(BackEndEntities context)
, dann haben Sie Ihre master-thread (den machen alle diese Kind-threads) erstellen und pflegen Sie eine BackEndEntities Rahmen weitergeben, um Ihre Kinder. Auch sicher sein, dass Sie loszuwerden, IhreAgentController
s undOrderController
s, sobald Sie fertig sind mit Ihnen, und nie, nie, nie Wiederverwendung außerhalb einer Methode. Der Umsetzung einer guten inversion of control framework Ninject wie oder StructureMap können diese viel einfacher.