2009-08-28 5 views
32

I verwendet Transaktion setzen Timeouts von TransactionOptions.Timeout mit, haben aber für eine einfache Wartung zu verwenden, die Config-Ansatz entschieden:Standard Transaction Timeout

<system.transactions> 
    <defaultSettings timeout="00:01:00" /> 
    </system.transactions> 

Natürlich nachdem er dies wollte ich um zu testen, dass es funktionierte, reduzierte das Timeout auf 5 Sekunden und führte dann einen Test aus, der länger dauerte - aber die Transaktion scheint nicht abzubrechen! Wenn ich den Test so einstelle, dass TransactionOptions.Timeout auf 5 Sekunden gesetzt wird, funktioniert der Test wie erwartet

Nach der Untersuchung scheint das Problem mit TransactionOptions.Timeout in Verbindung zu stehen, obwohl ich es nicht mehr verwende.

Ich brauche immer noch TransactionOptions, so dass ich IsolationLevel einstellen kann, aber ich nicht mehr den Timeout-Wert festlegen, wenn ich dieses Objekt nach der Erstellung betrachten, ist der Zeitüberschreitungswert 00:00:00, was unendlich entspricht . Bedeutet dies, dass mein in der Konfigurationsdatei gesetzter Wert ignoriert wird?

Fassen wir zusammen:

  • Ist es unmöglich, die Config Einstellung zu mischen, und die Verwendung von TransactionOptions
  • Wenn nicht, gibt es eine Möglichkeit, die Konfigurationseinstellung zur Laufzeit zu extrahieren, und die Verwendung dies, um die Timeout-Eigenschaft
  • [Bearbeiten] OR Legen Sie die Standard-Isolationsstufe ohne TransactionOptions
+0

In welcher Konfigurationsdatei haben Sie diesen Satz? In welchem ​​Konfigurationsabschnitt? – PVitt

+0

In App.confing direkt unter dem root. Auch in web.config, aber der obige Test war für app.config. – MattH

Antwort

44

Sie können Syst erfolgen mischen em.transaction Konfigurationseinstellungen und die Verwendung der TransactionOption Klasse, aber es gibt einige Dinge, die Sie beachten müssen.

Wenn Sie die TransactionOption und geben Sie einen Timeout Wert, der Wert wird über die System.Transactions/defaultTimeout Wert verwendet werden.

Das oben genannte ist der Kern des Problems in Ihrem Fall, denke ich. Sie verwenden die TransactionOption, um die Isolation Ebene anzugeben, und als Nebeneffekt erhalten Sie eine infinite Timeout Wert, da unendlich ist der Standardwert Timeout für TransactionOption, wenn es nicht angegeben ist. Obwohl ich mir nicht ganz sicher bin, warum das so ist ... wäre es sinnvoll, das Standard-Transaction-Timeout zu verwenden.

Sie können eine eigene Helper-Klasse TransactionOptions implementieren, die Standardwerte enthält, die von app.config (falls gefunden) oder Standardwerte für eine TransactionOption-Klasse, die verwendet werden kann, verwendet werden.

In jedem Fall können Sie dies dennoch begrenzen, indem Sie den Wert system.transaction/machineSettings/maxTimeout verwenden. Dies ist eine administrative Einstellung und kann nur über die Datei machine.config konfiguriert werden. Sie erhalten eine ConfigurationException, wenn Sie es aus app/web.config versuchen.

<system.transactions> 
    <machineSettings maxTimeout="00:00:30" /> 
</system.transactions> 

Mit dem maxTimeout Satz, egal welche Timeout-Wert, den Sie angeben, wird der Maximalwert auf den maxTimeout Wert begrenzt werden. Der Standardwert für maxTimeout ist 00:10:00 oder 10 Minuten. Sie haben also bei einer Transaktion nie eine unbegrenzte Zeitüberschreitung.

Sie können die Transaktion IsolationLevel explizit für die Datenbankverbindung festlegen, die Sie innerhalb der Transaktion verwenden. Etwas wie das?

var connectionString = "Server=.;Database=master;Trusted_Connection=True;"; 

      using (var scope = new TransactionScope(TransactionScopeOption.Required)) 
      { 
       using (var conn = new SqlConnection(connectionString)) 
       { 
        conn.Open(); 
        var sqlTransaction = conn.BeginTransaction(System.Data.IsolationLevel.Serializable); 

        // do database work 
        // 
        sqlTransaction.Commit(); 


       } 

       // do other work.. 
       // 

       scope.Complete(); 

      } 

In Ihren Tests müssen Sie möglicherweise sicherstellen, dass Sie neu erstellen, damit die app.config neu generiert wird. In meinen Tests schien es, dass ich den * .vshost.exe-Prozess beenden musste, damit er die Konfigurationsänderung der system.transaction-Konfiguration übernehmen konnte - obwohl ich denke, dass das ein Zufallstreffer gewesen sein könnte. Just fyi ..

1

meine aktuellen Gedanken weglegen:

  • Es ist unmöglich, die Konfigurationseinstellung zu mischen, und die Verwendung von TransactionOptions
  • Die einzige Möglichkeit, die Konfigurationseinstellung zur Laufzeit zu extrahieren ist die App zu lesen. Config als XML-Datei
  • die Standardisolationsebene kann nur über Transaktionsoptionen oder im Service-Level in WCF mithilfe von Attributen
+1

Zum zweiten Aufzählungspunkt: Es gibt eine API für den Zugriff auf die Konfigurationsdatei.Siehe den Code in meiner Antwort für eine Möglichkeit, es zu tun. Sie müssen nicht darauf zurückgreifen, es als XML-Datei zu lesen. –

6

Die Einstellung der Konfigurationsdatei wird ignoriert, wenn TransactionOptions verwendet wird. Beim Erstellen eines TransactionScope wird in den meisten Fällen eine Instanz von CommittableTransaction erstellt. Der no arg-Konstruktor von CommittableTransaction verwendet die Config-Dateieinstellung als Standard-Timeout. TransactionScope-Konstruktoren, die TransactionOptions oder TimeSpan verwenden, rufen eine der Überladungen der CommitableTransaction-Klasse und nicht die no arg-Version auf. Wenn Sie diesen Wert verwenden möchten, müssen Sie ihn selbst aus der Konfigurationsdatei holen.

Wenn ich in das stieß ich den folgenden Code in eine kleine TransactionOptionsFactory-Klasse.


Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 
ConfigurationSectionGroup sectionGroup = configuration.GetSectionGroup("system.transactions"); 
DefaultSettingsSection defaultSettings = (DefaultSettingsSection) sectionGroup.Sections["defaultSettings"]; 
TransactionOptions options = new TransactionOptions(); 
options.Timeout = defaultSettings.Timeout; 
options.IsolationLevel = IsolationLevel.ReadCommitted; 
+0

Entschuldigung Mike, ich hätte Ihnen die Prämie zugesprochen, aber ich war anscheinend eine Stunde hinter der Kopfgeld-Deadline. Diese Lösung würde mein Problem sehr gut lösen. Schade, dass die API hier nicht klarer ist. – MattH

+0

Keine Sorgen MattH. Ich bin nur froh, dass es geholfen hat. –

46

Sie können das (validierte) Standard-Timeout von der Konfiguration mit TransactionManager.DefaultTimeout abrufen.

TransactionOptions ist eine Struktur, die Timeout- und Isolationsstufe kapselt.Wenn ein struct mit dem Standard-Konstruktor initialisiert wird, wird es immer die Strukturkomponenten auf ihre Standardwerte initialisiert werden:

TransactionOptions transactionOptions = new TransactionOptions(); 
transactionOptions.Timeout == default(TimeSpan); // TimeSpan.Zero 
transactionOptions.IsolationLevel == default(IsolationLevel); // IsolationLevel.Serializable 

Wenn Sie eine IsolationLevel angeben möchten und die Standard-Timeout verwenden:

new TransactionOptions() 
{ 
    IsolationLevel = IsolationLevel.Serializable, // Use whatever level you require 
    Timeout = TransactionManager.DefaultTimeout 
}; 
+0

Das war die Antwort, auf die ich immer gehofft hatte! Leider ist es zu spät für mich, Ihnen die Antwort zu geben, aber TransactionManager.DefaultTimeout ist definitiv das, was ich wollte. Danke fürs Schreiben! – MattH

+1

Ich bemerkte auch, dass Microsoft diese Technik auch in ihrer [Dokumentation zu System.Transactions] (http://msdn.microsoft.com/en-us/library/ms973865.aspx) verwendet. Danke für die nützlichen Informationen! –

+0

FWIW Groveling in ILSpy zeigt einen Standard von 1 Minute in .NET 4.0, denken Sie daran, dies ist ein Implementierungsdetail, also Änderungen vorbehalten, verwenden Sie die obigen, um diesen Wert zu überprüfen !: // System.Transactions.Configuration.DefaultSettingsSection [ConfigurationProperty ("Zeitüberschreitung", DefaultValue = "00:01:00"), TimeSpanValidator (MinValueString = "00:00:00", MaxValueString = "10675199.02: 48: 05.4775807")] – aolszowka

9

pro Reflektor Die Grundregeln für das Festlegen eines Transaktionszeitlimits mit den Konstruktoren TransactionScope lauten wie folgt:

Die DefaultTimeOut von der ersten Regel bestimmt wird, unter dem erfüllt ist:

  • wenn der Konstruktor einen TimeSpan Parameter hat, die DefaultTimeout der, dass Parameter
  • ist, wenn der Konstruktor ein TransactionOption Parameter hat, die DefaultTimeout ist transactionOption.TimeOut
  • Wenn der Konstruktor über einen TransactionScopeOption-Parameter verfügt, ist DefaultTimeout scopeOption.TimeOut
  • Wenn der Konstruktor keinen Timeout-Parameter hat, ist DefaultTimeout der in der App- oder Webkonfigurationsdatei angegebene Wert.
  • andernfalls ist DefaultTimeOut 1 Minute.

Die maxTimeout ist 10 Minuten, wenn nicht ein anderer Wert in dem machine.config angegeben ist.

Das effektive Timeout für die Transaktion ist kleiner als MaxTimeOut und DefaultTimeOut, die größer als Null ist. Wenn sowohl MaxTimeOut als auch DefaultTimeOut Null sind, ist das effektive Timeout die Anzahl der Ticks, die durch long.MaxValue (das Unendliche) dargestellt werden. Wenn die TransactionScope-Instanz keine neue Transaktion erstellt, weil entweder eine Transaktion in ihren Konstruktor übergeben wird oder weil die Transaktionsbereichsoption dies nicht erfordert (z. aber ein timeOut Parameter wird noch im Konstruktor übergeben, ein Timer wird gestartet. Nach Ablauf der Zeitüberschreitung wird die Methode TimeOut() der zugrunde liegenden Transaktion aufgerufen. Die Eigenschaften DefaultTimeOut und MaxTimeOut werden in diesem Fall nicht verwendet.

Wenn die transactionScopeOption == TransactionScopeOption.Supress, wird das Timeout ignoriert und hat keine Auswirkungen.

Es ist auch möglich, die maxTimeout in der App/Web-Konfigurationsdatei zu definieren, wenn der entsprechende Abschnitt in der machine.config außer Kraft gesetzt wird (beachten Sie die Werte der allowDefintion und allowExeDefinition Attribute):

<sectionGroup name="system.transactions" type="System.Transactions.Configuration.TransactionsSectionGroup, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null"> 
    <section name="defaultSettings" type="System.Transactions.Configuration.DefaultSettingsSection, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null"/> 
    <section name="machineSettings" type="System.Transactions.Configuration.MachineSettingsSection, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null" allowDefinition="MachineToApplication" allowExeDefinition="MachineToApplication"/> 
</sectionGroup> 

für schnelle Referenz, hier ist der Transactionbauer:

public TransactionScope(Transaction transactionToUse, TimeSpan scopeTimeout, EnterpriseServicesInteropOption interopOption); 
public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions, EnterpriseServicesInteropOption interopOption); 
public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions); 
public TransactionScope(TransactionScopeOption scopeOption, TimeSpan scopeTimeout); 
public TransactionScope(Transaction transactionToUse, TimeSpan scopeTimeout); 
public TransactionScope(TransactionScopeOption scopeOption); 
+0

Super Antwort! – buckley

1
void Main() 
{ 
    var maximumTimeout = TransactionManager.MaximumTimeout;//This step is necessary to init _maximumTimeout value, 

    FieldInfo fieldInfo = typeof(TransactionManager).GetFields(BindingFlags.NonPublic | BindingFlags.Static).Single(item => item.Name == "_maximumTimeout"); 
    var customMaximumTimeout = TimeSpan.FromHours(1); 
    fieldInfo.SetValue(null, customMaximumTimeout); 
    maximumTimeout = TransactionManager.MaximumTimeout; 

    Console.WriteLine(maximumTimeout);//01:00:00 
    // use TransactionScope 
} 
+0

Wie Franz prägnant darauf hinweist - können Sie das mit Reflektion tun. Ich habe eine andere Methode in den Kommentaren dieses MSDN-Artikels gefunden: http://blogs.msdn.com/b/ajit/archive/2008/06/18/override-the-system-transactions-default-timeout-of-10- minutes-in-the-code.aspx # 10417962 - Leider ist die DevOps-Situation in meiner Firma nicht ganz so, wie ich sie brauche. Daher habe ich keine einfache Möglichkeit, die machine.config auf allen Verarbeitungsknoten zu aktualisieren Lassen Sie die Einstellungen für zukünftige Einstellungen gelten. Die Verwendung von Reflektion ist ein guter Workaround für mich. –