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
。它对数据库结构进行了一些必要的更改。例如它
删除自动增加字段
在删除之前保存这些键并以所需的顺序/位置重新创建
conn
是SqlConnection
已经打开,除此之外我没有使用任何连接
cmd
是conn.CreateCommand()
除了这个
我从不在整个过程中关闭连接,但是当他们完成工作时,SqlDataReader将在configuration
函数中关闭。
答案 0 :(得分:6)
对数据库结构的更改不是事务性的,因此您无法回滚创建新表,例如
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(考虑the default constructor is broken)。如果使用SqlConnection.BeginTransaction,最好还是依赖于IDisposable:
using (SqlTransaction trn = conn.BeginTransaction())
{
...
trn.Commit ();
}
System.Transactions应该受到青睐,因为它们不依赖于代码规则,事务范围中的任何代码SqlClient都会自动注册。
btw有错误的配置函数引发,不返回false。
关于潜在的实际问题:如何处理无法在单个事务中注册的冗长,复杂的迁移(例如,它只能生成太多日志)。答案是唯一可行的选择是在迁移开始时进行数据库备份,如果迁移失败,则从此备份恢复。为每次迁移操作提供手动,测试和可靠的补偿操作以撤消迁移的替代方案非常困难,错误,并且最终不必要,因为从备份恢复是如此简单和可证明正确。
答案 1 :(得分:1)
这可以通过使用TransactionScope来完成,而不是在代码中创建SqlTransaction。像这样:
using (TransactionScope transaction = new TransactionScope())
{
...perform your database action here
scope.Complete()
}