5
private void btnConfigure_Click(object sender, EventArgs e)
{
    try
    {
        dbConfigure dc = new dbConfigure();
        SqlTransaction tr = conn.BeginTransaction();
        cmd.Transaction = tr;
        if (dc.configuration(cmd, ps.tableNames))
            tr.Commit();
        else
        {
            tr.Rollback();
            mesg.show("Transaction is Rolled back");
        }
    }
    catch (Exception ex)
    {
        mesg.show(ex.Message);
    }
}

如果我在configuration方法的任何地方遇到问题,那么它会返回 false,我可以看到该消息Transaction is Rolled Back。但实际上事务并没有完全回滚,并且尽管回滚,但该函数对数据库结构所做的一些更改仍然存在,这是非常不希望的。我的问题是事务回滚发生故障的可能性是什么?

除了共享(以上)方法外,我的项目中没有其他任何交易

小细节

我正在调用configuration我班级的一个非常冗长/复杂的函数dbConfigure。它对数据库结构进行了一些必要的更改。例如它

  1. 丢弃外键
  2. 删除主键
  3. 删除自动增量字段

    它在删除之前保存这些键并以所需的顺序/位置重新创建

conn是一个SqlConnection已经打开的,除此之外我没有使用任何连接

cmdconn.CreateCommand()除了这个,我在任何地方都没有使用任何命令吗

在整个过程中我从不关闭连接,但是 SqlDataReader 在configuration完成工作时会关闭功能。

4

2 回答 2

7

对数据库结构的更改不是事务性的,因此您不能回滚创建新表,例如

BS。大多数 DDL 是事务性的,可以回滚。只有涉及与非事务性组件(如文件系统,例如将新文件添加到数据库)交互的更改不能回滚。如果在活动事务中调用任何非事务性 DDL,也会非常明确地引发异常。

添加和修改表是非常明确的事务性的,可以通过一个示例轻松说明:

begin transaction;
create table foo (a int);
select * from sys.tables where object_id = object_id('foo');
rollback;
select * from sys.tables where object_id = object_id('foo');

因此问题在于 OP 缺少代码,未发布的部分。

作为一般评论,应尽可能使用 System.Transactions (考虑到默认构造函数已损坏)。如果使用 SqlConnection.BeginTransaction 最好还是依赖 IDisposable:

using (SqlTransaction trn = conn.BeginTransaction())
{
   ...
   trn.Commit ();
}

System.Transactions 应该受到青睐,因为它们不依赖于代码规则,事务范围内的任何代码 SqlClient 都将自动注册。

顺便说一句,配置函数在错误时引发,而不是返回 false。

关于潜在的真正问题:如何处理无法在单个事务中注册的冗长、复杂的迁移(例如,它可能会生成太多日志)。答案是唯一可行的选择是在迁移开始时进行数据库备份,如果迁移失败,则从该备份中恢复。为每个迁移操作提供手动、经过测试和可靠的补偿操作以撤消迁移的替代方法非常困难、容易出错,并且最终是不必要的,因为从备份恢复非常简单且可证明是正确的。

于 2012-11-15T12:14:37.430 回答
1

这可以通过使用 TransactionScope 来完成,而不是在您的代码中创建 SqlTransaction。像这样的东西:

using (TransactionScope transaction = new TransactionScope())
{
    ...perform your database action here

    scope.Complete()
}
于 2012-11-15T11:56:59.517 回答