nod*_*ots 5 c# sql-server-2005
有没有办法在事务中添加检查约束,并且在故障回滚到上一个保存点的情况下(而不是回滚整个事务)?
在我的情况下,当ALTER TABLE ... ADD CONSTRAINT命令失败时,事务无法回滚到保存点(尝试这样做会抛出InvalidOperationException).
概述以证明关键点:
SqlTransaction transaction = connection.BeginTransaction();
// ... execute SQL commands on the transaction ...
// Create savepoint
transaction.Save("mySavepoint");
try
{
// This will fail...
SqlCommand boom = new SqlCommand(
"ALTER TABLE table WITH CHECK ADD CONSTRAINT ...",
connection,
transaction);
boom.ExecuteNonQuery();
}
catch
{
// ...and should be rolled back to the savepoint, but can't.
try
{
transaction.Rollback("mySavepoint");
}
catch (InvalidOperationException)
{
// Instead, an InvalidOperationException is thrown.
// The transaction is unusable and can only be rolled back entirely.
transaction.Rollback();
}
}
Run Code Online (Sandbox Code Playgroud)
这里是可以运行的可运行的演示代码(需要一个名为"test"的数据集):
public class Demo
{
private const string _connectionString = "Data Source=(local);Integrated security=true;Initial Catalog=test;";
private const string _savepoint = "save";
private static readonly string _tableName = DateTime.Now.ToString("hhmmss");
private static readonly string _constraintName = "CK" + DateTime.Now.ToString("hhmmss");
private static readonly string _createTable = "CREATE TABLE [dbo].[" + _tableName + "] ([one] [int] NULL,[two] [int] NULL) ON [PRIMARY]";
private static readonly string _insert1 = "INSERT INTO [" + _tableName + "] VALUES (1,1)";
private static readonly string _addConstraint = "ALTER TABLE [dbo].[" + _tableName + "] WITH CHECK ADD CONSTRAINT [" + _constraintName + "] CHECK (([one]>(1)))";
private static readonly string _insert2 = "INSERT INTO [" + _tableName + "] VALUES (2,2)";
public static void Main(string[] args)
{
// Example code! Please ignore missing using statements.
SqlConnection connection = new SqlConnection(_connectionString);
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
SqlCommand createTable = new SqlCommand(_createTable, connection, transaction);
createTable.ExecuteNonQuery();
// Create savepoint
transaction.Save(_savepoint);
SqlCommand insert1 = new SqlCommand(_insert1, connection, transaction);
insert1.ExecuteNonQuery();
try
{
// This will fail...
SqlCommand boom = new SqlCommand(_addConstraint, connection, transaction);
boom.ExecuteNonQuery();
}
catch
{
// ...and should be rolled back to the savepoint, but can't
transaction.Rollback(_savepoint);
}
SqlCommand insert2 = new SqlCommand(_insert2, connection, transaction);
insert2.ExecuteNonQuery();
transaction.Commit();
connection.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
我认为您不能在脚本和 C# 中混合使用保存点。我执行以下 SQL:
BEGIN TRANSACTION
INSERT INTO Foos (Fooname)
VALUES ('Bar1')
SAVE TRANSACTION MySavePoint;
INSERT INTO Foos (FooName)
VALUES ('Bar2')
ROLLBACK TRANSACTION MySavePoint
COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)
这适用于 SQL,并且适用于以下代码:
using (SqlConnection conn = new SqlConnection("connectionString"))
{
conn.Open();
using (SqlTransaction trans = conn.BeginTransaction())
using (SqlCommand comm = new SqlCommand("The Above SQL", conn, trans))
{
comm.ExecuteNonQuery();
trans.Commit();
}
}
Run Code Online (Sandbox Code Playgroud)
如果您尝试这样做,trans.Rollback("MySavePoint");
它将失败,因为trans
对象不受保存点的控制 - 它不知道这一点。
如果将 SQL 拆分为两个独立的插入并使用以下代码:
using (SqlConnection conn = new SqlConnection("connectionString"))
{
conn.Open();
using (SqlTransaction trans = conn.BeginTransaction())
using (SqlCommand comm1 = new SqlCommand("INSERT INTO Foos(fooName) VALUES('Bar1')", conn, trans))
using (SqlCommand comm2 = new SqlCommand("INSERT INTO Foos(fooName) VALUES('Bar2')", conn, trans))
{
comm1.ExecuteNonQuery();
trans.Save("MySavePoint");
comm2.ExecuteNonQuery();
trans.Rollback("MySavePoint");
trans.Commit();
}
}
Run Code Online (Sandbox Code Playgroud)
它将按您的预期工作。
请注意,始终处置实现的对象IDisposable
- 最好在using
声明中。
进一步阅读:
http://www.davidhayden.com/blog/dave/archive/2005/10/15/2517.aspx
更新:使用示例代码对此进行了一段时间的研究后,看起来由于来自 SQL 的错误,事务正在回滚并且变得不可用。正如另一个答案中所述,似乎与 SQL 结合使用时,由于某些错误,无论保存点如何,事务都会被强制回滚。唯一的办法是重新排序针对数据库运行的命令,而不依赖于保存点,或者至少不依赖于保存点中的该操作。
归档时间: |
|
查看次数: |
3323 次 |
最近记录: |