C# IDBTransation.Commit在事务完成之前返回
我有一个服务器(很少)动态创建数据库行以适应用户配置的数据模型。在启动过程中,服务器可能需要创建大约1000行以及多个插入到现有表中 完成所有这些操作后,它将提交事务并向可能正在侦听的任何人发送有关新数据模型的通知。问题是,transaction.Commit()似乎在数据库实际完成更改之前返回,因此如果客户端在发送通知后向服务器发出请求,则客户端可能会得到一个空结果。我的假设是,等待transaction.Commit()将确保事务全部完成并提交 客户端获得空结果的原因是,当不执行DDL操作时,数据库正在使用快照隔离,因此很明显,快照是在DDL操作完成之前(但在transaction.commit返回之后)拍摄的 操作顺序为:C# IDBTransation.Commit在事务完成之前返回,c#,sql-server,ado.net,ddl,C#,Sql Server,Ado.net,Ddl,我有一个服务器(很少)动态创建数据库行以适应用户配置的数据模型。在启动过程中,服务器可能需要创建大约1000行以及多个插入到现有表中 完成所有这些操作后,它将提交事务并向可能正在侦听的任何人发送有关新数据模型的通知。问题是,transaction.Commit()似乎在数据库实际完成更改之前返回,因此如果客户端在发送通知后向服务器发出请求,则客户端可能会得到一个空结果。我的假设是,等待transaction.Commit()将确保事务全部完成并提交 客户端获得空结果的原因是,当不执行DDL操作时
编辑:清晰。这是“快照隔离”的自然行为。检查此链接: 当另一个会话读取相同的数据时,返回在读取事务开始时提交的数据版本
您必须终止会话,以便其他事务处理可以读取它。或者将其更改为“Read Committed”。正如我们在评论中所指出的,造成这种情况的一个可能原因是挂起的外部事务。如下列文件所述: 在嵌套事务中使用时,提交内部事务 不要释放资源或使其修改永久化。数据 只有在 外部事务已提交。每次提交事务都是在 @@TRANCOUNT大于1,只是将@TRANCOUNT减1。 当@TRANCOUNT最终减为0时,整个外部 事务已提交。因为事务_名称被 数据库引擎,发出引用数据库名称的提交事务 存在未完成的内部事务时的外部事务 仅将@@TRANCOUNT递减1
因此,尽管成功执行了
Commit()
,但如果存在外部事务,则在外部事务也提交之前,不会将任何更改保留到数据库。我得到快照隔离将读取最新完成事务的状态。我的问题是,DDL事务没有在我预期的时间内完成,因此我开始发送通知太早,因此客户端请求(即快照隔离)读取了错误的数据。我的问题在于写入(而不是等待它完成),而不是读取。因为,在快照隔离中,行的当前版本被复制到tempDb。若有人想读取它,数据库将返回旧数据。这样做是为了防止锁定。我的建议是尝试将隔离级别更改为committed,以锁定未提交的行。但在ms sql server中,有一种方法可以克服这个问题,在select语句的末尾添加“with(nolock)”,实际上没有“太早”的说法。除非结束会话,否则将读取旧数据。服务器将提交事务。然后关闭与数据库的连接。然后它发出通知。然后,客户端向服务器发出请求,服务器将创建一个新会话(快照隔离)并读取数据。如果我读取提交的锁,将确保后者读取等待。但我确实需要使用快照隔离。我的问题是,IDbTransaction.Commit在数据完全提交之前返回。该引号中没有任何内容表明您将在整个会话中读取相同的数据。“返回读取事务开始时的数据版本”-不是在会话开始时。可能您同时有一个外部事务正在进行?然后,在外部事务提交之前,您的提交实际上不会应用更改。这当然是一种可能性(这是一个非常成熟的框架,因此不太容易导航),但我相当确定情况并非如此。不过,我将进行调查——正如我在下面所写的,不过,在我提交之后,我会关闭连接,因此父事务很难阻止。如果我们假设情况并非如此,那么这似乎只有在涉及DDL时才会发生。正常的数据库更新似乎在提交完成后完全结束。当您说DDL时,是指CREATE语句吗?DDL将使用模式修改锁并阻止其他会话,而不管事务隔离级别如何,所以您可能指的是DML(插入)。我建议您运行跟踪来验证事务的顺序。这些症状表明客户端请求(#5)是在步骤#1之前启动的快照事务中完成的。我的意思是DDL-但不在我从中读取的表上。我在一些表中添加列,在其他表中添加行,以便在单个事务中记账@Evk我确实有一个外部TransactionScope,但是压制它并不能解决问题。@Evk-确实是外部TransactionScope造成了麻烦!请注意,通过在SQL连接字符串中添加Enlist=False,可以忽略外部事务。