SqlTransaction中的SqlDataAdapter.Fill() – 这是一个不好的做法吗?

因为我有一个带有DataSet QueryDB(string spName, DBInputParams inputParams)方法的“DB util”类,我用它来调用数据库,所以我想重用这个方法来支持事务调用。

所以,最后我将在SqlTransaction中有一个SqlDataAdapter.Fill。 这会是一种不好的做法吗? 因为我很少在事务中看到DataAdapter.Fill的使用,更常见的是ExecuteReader()。 有没有捕获?

Edit1:事情是我的事务内部经常需要检索一些数据(例如自动ID)…这就是为什么我想把它作为DataSet。

Edit2:奇怪的是当我在2个不同进程的for循环(10000)中使用这种方法时,我得到“事务(进程ID 55)在锁资源上与另一个进程死锁,并被选为死锁牺牲品。重新运行事务“。 。 这是正确的行为吗?

Edit3 :(回答Edit2)我正在使用IDENT_CURRENT('XTable') ,这是错误的来源。 在我回到SCOPE_IDENTITY() ,一切都已经解决了。

不是一个坏习惯。 要记住的一件事是,所有语句都将使用隐式事务,它们将在语句结束时自动提交。 这是一个SELECT(在Fill使用的SELECT中)将始终使用一个事务,问题是它是否必须自己启动它或者它将使用现有的事务。

SELECT在隐式事务中与明确事务中获取的锁的数量,类型和持续时间之间是否存在任何差异? 在默认事务模型(READ COMMITTED隔离) NO下 ,没有。 行为是相同的,无法区分。 在其他隔离级别(可重复读取,可序列化)下,存在差异,但这是发生所需更高隔离级别的必要差异,并且在必要时使用显式事务是实现此所需隔离级别的唯一方法。

此外,如果SELECT必须读取待处理(尚未提交)的事务的影响,如在您的示例中(回读生成的ID) ,则没有其他方法 。 SELECT 必须是生成ID的事务的一部分,否则它将无法看到那些未提交的ID!

但需要注意的是。 我相信你有一个很棒的工具可以让所有这些事务处理变得更加容易: System.Transactions 。 所有ADO.Net代码都是系统事务感知的,如果您只是声明一个TransactionScope ,它将自动将任何连接和命令注册到挂起的TransactionScope 。 也就是说,如果函数Foo声明一个TransactionScope然后调用函数Bar,如果Bar执行任何 ADO.Net操作,它将自动成为Foo中声明的TransactionScope一部分,即使Bar 没有明确地执行任何操作TransactionScope挂钩到线程上下文中,Bar调用的所有ADO.Net调用将自动检查此上下文并使用它。 请注意,我的意思是任何 ADO.Net调用,包括Oracle提供者调用。 虽然有一个警告: 使用新的TransactionScope()Considered Harmful : TransactionScope的默认构造函数将创建一个可序列化的事务,这是过度的。 您必须使用获取TransactionOptions对象的构造函数并将行为更改为ReadCommitted。 使用TransactionScope的第二个问题是你必须非常小心你如何管理连接:如果你在一个范围内打开多个连接,那么它们将被注册到分布式事务中,这很慢并且需要配置MSDTC,并且引导各种难以调试的错误。 但总体而言,我认为使用TransactionScope的好处超过了问题,并且结果代码总是比明确传递IDbTransaction更优雅。

这是一种不好的做法,因为当事务处于打开状态时,您进行更改的记录/页面/表在事务持续期间被锁定。 填充只会使整个过程使这些资源锁定的时间更长。 根据您的sql设置,这可能会阻止对这些资源的其他访问。

也就是说,如果有必要,就必须实现惩罚。