C# 事务不在c中回滚#

C# 事务不在c中回滚#,c#,sql-server,transactions,rollback,C#,Sql Server,Transactions,Rollback,如果我在configuration方法中的任何地方遇到问题,那么它将返回false,并且我可以看到消息事务已回滚。但实际上,事务并没有完全回滚,并且该函数对数据库结构所做的一些更改仍然存在,尽管回滚是非常不希望的。我的问题是事务回滚出现故障的可能性是什么? 在我的项目中,除了共享(上述)方法外,我没有其他任何事务 小细节 我正在调用类dbConfigure的一个非常长/复杂的函数configuration。它对数据库结构进行了一些必要的更改。e、 g.它 丢钥匙 删除主键 删除自动递增字段 它在

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

在我的项目中,除了共享(上述)方法外,我没有其他任何事务

小细节

我正在调用类
dbConfigure
的一个非常长/复杂的函数
configuration
。它对数据库结构进行了一些必要的更改。e、 g.它

  • 丢钥匙
  • 删除主键
  • 删除自动递增字段

    它在放置前保存这些关键点,并按所需顺序/位置重新创建

  • conn
    是一个已经打开的
    SqlConnection
    ,除此之外,我在任何地方都不使用连接

    cmd
    conn.CreateCommand()
    除此之外,我在任何地方都不使用命令


    在整个过程中,我从未关闭连接,但是SqlDataReader在执行其工作时会在
    配置中关闭。

    这可以通过使用TransactionScope而不是在代码中创建SqlTransaction来实现吗。大概是这样的:

    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);
        }
    }
    
    例如,对数据库结构的更改不是事务性的,所以不能回滚新表的创建

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

    添加和修改表是非常显式的事务性操作,可以很容易地用一个示例加以说明:

    using (TransactionScope transaction = new TransactionScope())
    {
        ...perform your database action here
    
        scope.Complete()
    }
    
    因此,问题在于OP缺少代码,部件未发布

    作为一般性意见,应尽可能使用System.Transactions(考虑到这一点)。如果使用SqlConnection.BeginTransaction,则最好依赖IDisposable:

    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');
    
    虽然事务不依赖于代码规则,但事务范围内的任何代码SqlClient都将自动注册

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


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

    非常感谢@Morten Jacobsen。我不这么想。所以我得到了答案。但是,如果有什么方法可以做到这一点,请你也给我指点一下好吗?如果另一个创建表失败,是否意味着回滚创建表?是@GeorgeStocker。虽然你说的链接似乎对解决我的问题没有多大帮助。然而,我很高兴通过这个问题我学到了一些东西。最好的答案可能是帮助我找到一种方法来回滚数据库中的结构更改。但至少你的评论提供了一些指导和动力。你可以把它作为答案贴出来,如果我找不到更好的答案,我肯定会接受的。因为这是有效的回答,所以我删除了我之前的评论,因为正如Remus Rusanu指出的,在SQL Server中进行事务性DDL实际上是可能的。我的评论是基于Oracle数据库的,这是不可能的。可能是,但我认为不是。因为我被告知,结构上的更改是无法回滚的。可能有一些方法你是对的,这在SQL server中是可能的(我不知道)。。然而,您可能应该指出,据我所知,其特定于供应商的Oracle不允许这样做。由于OP没有指定要连接到哪个数据库,因此这种方法可能不可行。@MortenJacobsen:问题被标记为“sql server”,OP代码使用SqlClient组件。至于DDL transact-Capability,答案要复杂得多:但最终没有必要陷入困境,因为这个问题显然是针对某个特定供应商的。我明白了,我没有注意到标签。回答得好。我需要一些时间:)
    using (SqlTransaction trn = conn.BeginTransaction())
    {
       ...
       trn.Commit ();
    }