2016-12-07 13 views
0

In unseren SQL Server-Integrationstests werden Tests in einem TransactionScope umbrochen, das nach jedem Test zurückgesetzt wird, um die Datenbank in einem konsistenten Zustand zu halten.Postgres-, Npgsql- und Integrationstests mit Rollbacks

Mit Postgres (oder möglicherweise speziell Npgsql) scheint dies nicht möglich zu sein, da außerhalb einer einzelnen Verbindung ausgewählte Daten nicht festgeschriebene Daten lesen können (auch wenn innerhalb des nicht festgeschriebenen Transaktionsbereichs).

[Test] 
public void ImplicitEnlist() 
{ 
    var connectionString = ConnectionString + ";enlist=true"; 
    using (var scope = new TransactionScope()) 
    { 
     using (var conn = new NpgsqlConnection(connectionString)) 
     { 
      conn.Open(); 
      Assert.That(conn.ExecuteNonQuery(@"INSERT INTO data (name) VALUES('test')"), Is.EqualTo(1)); 
     } 
     using (var conn = new NpgsqlConnection(connectionString)) 
     { 
      // -> this is false 
      Assert.That(conn.ExecuteScalar(@"SELECT COUNT(*) FROM data"), Is.EqualTo(1)); 
     } 
     scope.Rollback(); 
    } 
} 

Kann jemand teilen, wie Leute diese Datenbanken mit Postgres nähern:

Das Basisszenario wird im Folgenden vereinfacht?

+0

Warum benötigen Sie separate Verbindungen für die Tests? –

+0

Bei den Integrationstests handelt es sich um sehr umfangreiche Funktionstests, bei denen keine Verbindung zwischen den zugrunde liegenden Klassen hergestellt wird. –

+0

Für Kontext, untersuche ich die Durchführbarkeit einer Migration von SQL Server zu Postgres und das war das erste Problem, das ich mit unserer Testsuite traf. –

Antwort

1

Copy-Paste Antwort vom github issue:

Ich glaube wirklich nicht, Dinge sollen in dem Weg zur Arbeit Sie denken. Wenn Sie zwei Verbindungen innerhalb desselben TransactionScope öffnen, führen Sie verteilte Transaktionen aus. PostgreSQL hat 2 verschiedene Verbindungen mit jeweils einer prepared transaction. Das bedeutet nun nicht, dass die beiden Verbindungen sich gegenseitig kennen oder dass die beiden vorbereiteten Transaktionen etwas miteinander verknüpft sind. Und da sie noch nicht festgeschrieben wurden, gilt die Transaktionsisolation und jede Verbindung kann die nicht festgeschriebenen Änderungen des anderen nicht sehen.

Zusammengefasst bedeuten verteilte Transaktionen, dass wenn Sie Complete() auf Ihrem TransactionScope aufrufen, das Zwei-Phasen-Commit-Protokoll verwendet wird, um sicherzustellen, dass beide Transaktionen festgeschrieben werden, oder keine. Es garantiert nicht, dass teilnehmende Transaktionen einander irgendwie bekannt sind.

Während ich ziemlich sicher bin, dass so etwas funktioniert, bin ich kein Experte in verteilten Transaktionen oder PostgreSQL-vorbereiteten Transaktionen - damit kann ich mich irren. Ich werde das schließen, werde aber wieder öffnen, wenn Sie irgendwelche Informationen finden, die dem widersprechen, was ich gesagt habe.

0

Der beste Weg, dies zu erreichen, erscheint Sicherungspunkte (https://www.postgresql.org/docs/9.1/static/sql-rollback-to.html) zu verwenden - das ist, wie Active setzt sie gegen Postgres/MySQL (http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html)

Nach weiteren in diesem Graben, es stellt sich heraus, haben wir abhängig gewesen auf einer SQL Server-Oberfläche bis jetzt. SQL Server 2008 (und .NET 3.5+) kann mehrere Verbindungen innerhalb einer Transaktion ohne MSDTC-Heraufstufung verarbeiten, sofern sie nicht gleichzeitig geöffnet sind - https://msdn.microsoft.com/en-us/library/ms172070(VS.90).aspx. Postgres hat in diesem Szenario nicht das gleiche Verhalten.

Wir beendeten unsere Abhängigkeit von Transaktionen für Rollback Prüfzustand Entfernen up (die eigenen Probleme sowieso es hatte) und stattdessen Respawn (https://github.com/jbogard/Respawn), die den db für uns stattdessen auf leeren Zustand zurückgesetzt.

Verwandte Themen