2016-03-23 11 views
0

Als wir letzten Freitag veröffentlicht, erhielt ich einen Fehler, den ich nicht auf Akzeptanz bekommt. Die Fehlermeldung lautet:NHibernate IStatelessSession Create Ausfall

could not execute update query[SQL: delete from dbo.MyTable where col1=? and col2=? and col3=? and col4=? and col5=?]

Mein C# -Code ist wie folgt:

var hqlDelete = "DELETE MyTable m WHERE m.Col1 = :var_1 AND m.Col2 = :var_2 AND m.Col3= :var_3 AND m.Col4 = :var_4 AND m.Col5= :var_5"; 
var deletedEntities = session.CreateQuery(hqlDelete) 
          .SetString("var_1", variable1) 
          .SetString("var_2", variable2) 
          .SetString("var_3", variable3) 
          .SetString("var_4", variable4) 
          .SetString("var_5", variable5) 
          .ExecuteUpdate(); 
transaction.Commit(); 
session.Close(); 

Nun, wie gesagt, der Fehler auslösen nicht, wenn sie auf Akzeptanz zu testen. Auch wenn ich mit der Produktionsdatenbank (Code von meinem Entwickler-Sitz) teste, funktioniert es auch ohne Probleme.

Der Code wird ausgelöst, wenn ich einen Web-Service und POST rufen eine „Messung“, um es. Der einzige Unterschied ist, dass ich den Dienst beim Testen anrufe, und bei der Produktion sendet ein anderes Unternehmen Messungen an den Web-Service.

Ich denke, es könnte etwas mit der Anzahl der Sitzungen/Transaktionen zu tun haben, aber das würde nicht wirklich erklären, warum die Variablen als ? in der Fehlermeldung angezeigt werden.

Irgendwelche Ideen? Gibt es mehr Informationen, die ich liefern könnte, damit Sie mir dabei helfen können?

Edit: InnerExeption ist

{"Transaction (Process ID 68) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction."}

+2

Erstens, zeigen Sie volle Ausnahme Stack .. dieser Teil oben wäre nur ein Anfang ... die echten und interessanten Informationen werden folgen ... –

+1

Wie von Radim, Ihre Fehlermeldung ist unzureichend. Es sagt nur, was es nicht kann. Normalerweise gibt es einige Gründe. Protokollieren Sie Details der Ausnahme, einschließlich ihrer InnerException. Wenn Sie nicht mehr haben, fügen Sie log4net hinzu, konfigurieren Sie es für die Protokollierung von mindestens Warnungen und höher, und NHibernate sollte dann detaillierte Protokolle über den Fehler ausgeben. –

+0

Ok danke. Ich hatte gehofft, das war ein typischer Fehler oder so. Es ist ein bisschen schwer zu debuggen, da ich einen Release-Plan einhalten muss (ich kann einmal im Monat veröffentlichen) und teste daher nur auf Akzeptanz. Also selbst wenn ich log4net hinzufüge, muss ich einen Monat warten, bevor ich sehen kann, was die Fehler sind. – Tjab

Antwort

1

Solving Deadlocks eine harte Sache sein kann, vor allem, wenn mit Hilfe eines ORM. Deadlocks treten normalerweise auf, weil Sperren für Datenbankobjekte nicht in derselben Reihenfolge von verschiedenen Prozessen (oder Threads) abgerufen werden, was dazu führt, dass sie aufeinander warten.

Ein ORM nicht geben Ihnen viel Kontrolle über Lock zu erwerben, um. Sie können Ihre Abfragen nachbearbeiten, dies könnte jedoch mühsam sein. Vor allem, wenn Caching bewirkt, dass einige von ihnen nicht auf DB treffen. Darüber hinaus sollte es mit der gleichen Reihenfolge für jede andere Anwendung mit derselben Datenbank durchgeführt werden.

Sie können Deadlock Fehler erkennen und tun, was die Botschaft sagen: den ganzen Prozess wiederholen. Mit NHibernate bedeutet dies, die aktuelle Sitzung zu verwerfen und die gesamte Arbeitseinheit erneut zu versuchen.

Wenn Ihre Datenbank SQL Server ist, gibt es eine Standardeinstellung, die stark Deadlocks Risiko erhöhen: die Sperrung von read committed snapshot mode. Wenn es in Ihrer Datenbank deaktiviert ist, können Sie Deadlock-Risiken erheblich reduzieren, indem Sie es aktivieren. In diesem Modus können Lesevorgänge unter Read Committed Isolation Level keine Lesesperren mehr ausgeben.

Sie können diese Einstellung überprüfen mit

select snapshot_isolation_state_desc, is_read_committed_snapshot_on 
    from sys.databases 
    where name = 'YourDbName' 

Sie können diese Einstellung mit

ermöglichen kann, auf dem Ziel db
alter database YourDbName 
    set allow_snapshot_isolation on 

alter database YourDbName 
    set read_committed_snapshot on 

Dies erfordert, die keine laufende Transaktion. Und das erfordert natürlich Administratorrechte für die DB.

Auf einer Anwendung, für die ich nicht die Möglichkeit aufweist, wurde diese Einstellung zu ändern, hatte ich eine schrullige Art und Weise zu gehen: NHibernate Standardisolationsmodus (connection.isolation configuration parameter) zu ReadUncommitted Einstellung. Mein Antrag wurde meist nur gelesen und ich war Erhöhung des Isolationsmodus explizit auf den wenigen Transaktionen mit Daten lesen, dann schreiben (session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted) mit gutem Beispiel verwendet wird).

Sie sollten auch die Isolationsmodi überprüfen, die derzeit von allen Anwendungen verwendet werden, die die Datenbank verwenden: verwenden einige von ihnen eine höhere Isolationsstufe als tatsächlich benötigt? (RepeatableRead und Serializable sollte nach Möglichkeit vermieden werden.) Dies ist ein zeitaufwändiger Prozess, da ein gutes Verständnis der Isolationsstufen erforderlich ist, während jeder Anwendungsfall untersucht wird, um festzustellen, welche geeignete minimale Isolationsstufe vorliegt.

+0

Danke für die sehr aufwendige Antwort! Die Snapshot-Isolation/Lesen-Commit ist tatsächlich auf false/0 gesetzt, und ich wusste von dieser Einstellung nichts. – Tjab

+1

Ich habe einen Punkt über den Read-Committed-Snapshot-Modus vergessen: es verursacht mehr Verwendung von Tempdb-Space. Ihr DBA sollte davon wissen. –

+0

Hmm, das muss ich mir auch anschauen. Die Datenbank selbst ist ziemlich groß und spricht im Moment über fast 400 Millionen Datensätze in einer Tabelle ... weiß nicht, ob es "je größer die Tabelle/db ist, desto mehr wird der Tempdb-Platz verwendet", aber wenn ja. :) – Tjab