将 SqlTransaction 与 SqlDataReader 一起使用

Posted

技术标签:

【中文标题】将 SqlTransaction 与 SqlDataReader 一起使用【英文标题】:Using SqlTransaction with SqlDataReader 【发布时间】:2015-06-17 15:40:08 【问题描述】:

网上有很多人在谈论它,但这似乎不起作用。这是我得到的例外:

 This SqlTransaction has completed; it is no longer usable.

这里是代码

 using (SqlConnection locationConnection = new SqlConnection(connectionString))
        
            locationConnection.Open();
            SqlTransaction transaction = locationConnection.BeginTransaction();
            SqlCommand cmd = new SqlCommand("
 Select stuff from table A
 Insert stuff into table B
 Delete stuff from table A", locationConnection, transaction); 

            using(SqlDataReader reader = cmd.ExecuteReader())
                    
                        while (reader.Read())
                        
                            //Doesn't matter
                                                    
                    

            //Exception happens here
            transaction.Commit();       
        

谁能解释为什么会这样?如果我将提交移动到 SqlDataReader 的范围内,则会出现数据读取器需要先关闭的异常。

编辑:我已经回答了我的问题,并会尽量记住在允许的几天内接受它。

【问题讨论】:

为什么你只使用一个选择语句的事务?这只是您的代码示例吗?你真的在这里进行了一些数据操作吗?没有理由只处理一个 select 语句。 仅供参考,如果您使用using 语句,则无需显式调用locationConnection.DisposelocationConnection.Close 我在进行更改之前选择了一个结果集,以便记录我所做的更改。 您不需要单独的选择和交易。您可以使用 OUTPUT 子句。此外,SqlTransaction 应该在 using 块中,SqlCommand 也应该如此。为什么你认为你必须先将其设置为null 我更专注于这个问题,但我将所有内容都移到了你提到的 using 语句上,问题仍然存在。 【参考方案1】:

问题是我的 DELETE 语句出现了 SqlException(外键问题)。这是关闭 sqlconnection 并结束事务,但它没有在我的代码中引发异常,因为 SELECT 语句工作正常。我已经解决了 Sql 问题并且代码工作正常。如果其他人遇到这种情况,他们应该能够像我一样做到这一点。

【讨论】:

【参考方案2】:

如果这些 SQL 本质上是单独的,那么您可以将它们包装在存储过程中并在过程中使用事务。然后在您的 C# 代码中调用该过程。另一种解决方案。

CREATE PROCEDURE usp_TransTest
AS
BEGIN

DECLARE @err INT

BEGIN TRAN
    Insert stuff into table B

    SELECT @err = @@ERROR
    IF (@err <> 0) GOTO ERR

    Delete stuff from table A

    SELECT @err = @@ERROR
    IF (@err <> 0) GOTO ERR
COMMIT TRAN

ERR:
PRINT 'Unexpected error occurred!'
    ROLLBACK TRAN
END

【讨论】:

如果您无法通过 SqlDataReader 使用事务,那么我会接受它作为答案。我可以在 C# 中拆分命令,以便在我担心事务之前进行选择。我只是更喜欢这样写,因为它是基于其余代码源最有意义的。

以上是关于将 SqlTransaction 与 SqlDataReader 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

使用 sqltransaction 插入表时选择数据

无法访问 SqlTransaction 对象以在 catch 块中回滚

SqlTransaction

CommandBuilder 和 SqlTransaction 插入/更新行

SqlConnection ,SqlTransaction,SqlCommand的常用法

将数据读取器与 sqltransactions 一起使用