2

如果我通过尝试创建现有表导致错误,则现有事务似乎已经自行回滚:

private void CreateSomeThings()
{
    SqlConnection SqlConn = new SqlConnection(ConnectionString);
    SqlConn.Open();

    (new SqlCommand("BEGIN TRANSACTION", SqlConn)).ExecuteNonQuery();

    try
    {
        (new SqlCommand("CREATE TABLE sometable ([some_id] [int] IDENTITY(1,1) NOT NULL)", SqlConn)).ExecuteNonQuery();

        // Create the table again, but carry on by catching the exception
        try
        {
            (new SqlCommand("CREATE TABLE sometable ([some_id] [int] IDENTITY(1,1) NOT NULL)", SqlConn)).ExecuteNonQuery();
        }
        catch (Exception)
        {
        }

        // If another exception is thrown
        (new SqlCommand("bingy bongy boo", SqlConn)).ExecuteNonQuery();

        (new SqlCommand("COMMIT TRANSACTION", SqlConn)).ExecuteNonQuery();
    }
    catch (Exception Ex)
    {
        try
        {
            // ... then this command will fail with "no corresponding BEGIN TRANSACTION"
            (new SqlCommand("ROLLBACK TRANSACTION", SqlConn)).ExecuteNonQuery();
        }
        catch (Exception Ex2)
        {
            throw;
        }
    }
}

我想了解发生了什么以及为什么。我希望事务回滚是我的责任 - 对于其他错误,它不会这样做:例如,如果我只是调用“bingy bongy”,则只有调用引发异常,然后我ROLLBACK在异常中没有任何问题。

4

2 回答 2

3

SQL Server 可以单方面决定回滚您的事务。这是 SQL Server 中的一个严重设计缺陷,因为您的应用程序永远无法知道事务是否仍处于活动状态。没有很好地记录哪些类型的错误回滚以及哪些类型的错误不回滚。例如,我想我记得唯一键违规和其他数据错误不会回滚。但其他人会。有些错误甚至会终止连接(这种情况很少见,不是设计缺陷)。

我建议您以这样一种方式编码,即在第一个错误时中止事务,然后失败或重试所有操作。这样可以省去很多麻烦。更喜欢每批执行一条语句,否则您可能会在事务之外运行第二条语句。

如果你真的想继续追查错误,你必须做两件事:

  1. 建立不回滚的错误白名单。在这种情况下,您可以继续前进。
  2. 检查SELECT @@TRANCOUNT交易是否仍然有效。
于 2013-10-21T13:24:47.883 回答
0

You need to pass a transaction object to every command you're using to make them take part in the same transaction.

The usual pattern is:

using (var conn = new SqlConnection("your connection string here"))
{
    SqlTransaction trans = null;
    try
    {
        conn.Open();
        trans = conn.BeginTransaction();

        using (SqlCommand command = new SqlCommand("command text here", conn, trans))
        {
            // do your job
        }
        trans.Commit();
    }
    catch (Exception ex)
    {
        try
        {
            // Attempt to roll back the transaction.
            if (trans != null) trans.Rollback();
        }
        catch (Exception exRollback)
        {
            // Throws an InvalidOperationException if the connection  
            // is closed or the transaction has already been rolled  
            // back on the server.
        }
    }
}
于 2013-10-21T11:16:22.103 回答