and*_*ter 8 c# sql-server postgresql transactions
我想在单个事务范围内打开多个连接,以便每个连接都可以看到先前连接所做的更改.
我需要这个用于测试 - 真正的代码写入数据库,测试代码验证数据是否实际插入/更新.最后,我回滚事务范围,以便真正的数据库不受影响.
这种方法在SQL Server中运行良好,但在PostgreSQL中似乎不起作用(我使用9.3与Npgsql提供程序),下面是一个小例子.
这是在事务范围内运行任意查询的帮助程序
private void RunQuery(string query, Action<IDataReader> process)
{
using (var connection = new NpgsqlConnection(Config.ConnectionString)) {
connection.Open();
connection.EnlistTransaction(Transaction.Current);
using (var command = connection.CreateCommand()) {
command.CommandText = query;
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
process(reader);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
..这里是测试代码 - 它插入到users表中,然后检查用户是否实际插入:
using (var scope = new TransactionScope()) {
//"tested scenario"
int id = 0;
RunQuery("INSERT INTO users (name) VALUES ('foo') RETURNING id;", reader => {
id = (int)reader.GetValue(0);
});
//checking
int id2 = 0;
RunQuery("SELECT id, name FROM users WHERE id=" + id, reader => {
id2 = (int)reader.GetValue(0);
});
Assert.That(id2, Is.Not.EqualTo(0));
}
Run Code Online (Sandbox Code Playgroud)
Postgres上面的测试失败,因为id2总是为零.我试过TransactionScope构造函数,TransactionOptions.ReadUncommitted但它似乎没有帮助.请注意,如果我针对SQL Server运行(更改NpgsqlConnection为SqlConection,用于SCOPE_IDENTITY检索id),那么一切正常并且id2不为零.
正如您所料,在Postgres的同一连接工作中选择,但我不需要,我的目标是在共享事务范围上使用多个连接.我也不需要多线程,这些连接按顺序发生.
首先是免责声明:虽然我对postgresql有点了解,但我对.NET知之甚少.
我怀疑你是在混淆两个相关但又独立的概念 - 分布式事务的概念和存在的事务隔离级别.
根据.NET文档,EnlistTransaction将连接添加到分布式事务中.分布式事务描述如下
分布式事务是影响多个资源的事务.对于要提交的分布式事务,所有参与者必须保证对数据的任何更改都是永久性的.尽管系统崩溃或其他无法预料的事件,变更仍然存在.如果即使单个参与者未能提供此保证,整个事务也会失败,并且会回滚对事务范围内的任何数据更改.
在数据库中,此类事务通过两阶段提交过程在数据库中实际上独立的事务之间实现.通过执行,所有参与的事务都进展到第一阶段的结束PREPARE TRANSACTION.一旦它们都处于这种状态,那么它们就可以通过执行完全提交COMMIT PREPARED.如果其中任何一个失败PREPARE TRANSACTION,那么它们都可以回滚ROLLBACK PREPARED.这可以保证它们全部被提交,或者它们都被回滚.
当使用.NET提供的中间件时,您没有看到任何这些细节:框架为您处理两阶段提交.
因此,您可能想知道这与您没有看到此分布式事务的一部分中所做的更改反映在另一部分中的事实有什么关系.答案可能一无所获.这两个事务实际上是完全分开的 - 实际上它们可能位于完全独立的数据库上.
您要实现的目标是 - 在提交之前能够看到一个事务中的另一个事务所做的更改 - 与事务隔离级别有关.
对您而言,坏消息是,您希望拥有的隔离级别是"未提交读取",这在postgresql中是不受支持的.
也许您需要在更高的层次上描述您想要实现的目标 - 可能还有另一种(可能更好的)方法来实现它.