在我们的SQL Server集成测试中,我们将测试包装在TransactionScope中,然后在每次测试后回滚以使数据库保持一致状态。
使用Postgres(或可能特别是Npgsql),这似乎是不可能的,因为单个连接之外的选择无法读取未提交的数据(即使在未提交的transactioncope中)。
基本情景简化如下:
[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();
}
}
有人可以分享人们如何使用Postgres数据库接近这个吗?
答案 0 :(得分:1)
来自github issue的答案的复制粘贴:
我真的不认为事情应该以你的思维方式运作。在同一TransactionScope中打开两个连接时,您将执行分布式事务。 PostgreSQL有2个不同的连接,每个连接都有一个prepared transaction。现在,这并不意味着两个连接彼此了解,或者两个准备好的事务在某种程度上是相互关联的。由于它们尚未提交,因此适用交易隔离,并且每个连接都无法看到其他未提交的更改。
总而言之,分布式事务意味着当您在TransactionScope上调用Complete()时,将使用两阶段提交协议来确保两个事务提交或不提交。它并不能保证参与的交易在某种程度上相互了解。
虽然我很确定这是事情的运作方式,但我不是分布式事务或PostgreSQL准备交易的专家 - 所以我可能错了。我会关闭这个,但如果你能找到任何与我所说的相反的信息,我会重新开启。
答案 1 :(得分:1)
在进一步深入研究之后,事实证明我们直到现在一直依赖于SQL Server。 SQL Server 2008(和.NET 3.5+)可以处理事务中的多个连接,而不需要MSDTC升级,只要它们不同时打开 - https://msdn.microsoft.com/en-us/library/ms172070(VS.90).aspx。 Postgres在这种情况下没有相同的行为。
我们最终删除了对事务的依赖,以便回滚测试状态(无论如何都有自己的问题),而是使用Respawn(https://github.com/jbogard/Respawn)将数据库重置为空状态代替我们