在C#循环中调用SQL存储过程时处理事务
我正在开发一个已经由其他开发人员开发的系统。 在该系统中,他们调用了一个存储过程,用于在C#中的循环侧插入记录,而不使用用户定义的表类型 我需要做的是在这个场景中添加一个事务。但问题是我不知道交易地点 我想知道它是在扭曲循环的C代码中,还是在存储过程中 SQL SERVER中的在C#循环中调用SQL存储过程时处理事务,c#,sql,sql-server,loops,stored-procedures,C#,Sql,Sql Server,Loops,Stored Procedures,我正在开发一个已经由其他开发人员开发的系统。 在该系统中,他们调用了一个存储过程,用于在C#中的循环侧插入记录,而不使用用户定义的表类型 我需要做的是在这个场景中添加一个事务。但问题是我不知道交易地点 我想知道它是在扭曲循环的C代码中,还是在存储过程中 SQL SERVER中的 BEGIN TRY BEGIN TRAN -- DO YOUR INSERT /UPDATE /DELETE HERE COMMIT TRAN T1 END TRY BEGIN CATCH -- // ROLL
BEGIN TRY
BEGIN TRAN
-- DO YOUR INSERT /UPDATE /DELETE HERE
COMMIT TRAN T1
END TRY
BEGIN CATCH
-- // ROLL BACK IF ERROR OCCURS
ROLLBACK TRAN T1
END CATCH
在C中#
你只能把它放在C#loop里面。在过程内启动的事务必须在过程退出之前提交。SQL Server在运行过程之前和之后检查,如果结果不匹配,则引发异常。因此,过程不可能启动必须由调用方提交的事务 最简单的方法是将C代码包装到事务范围中:
using(var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions() {
IsolationLevel = IsolationLevel.ReadCommitted
})) {
// Do the work here
scope.Complete();
}
请注意,传递
IsolationLevel=IsolationLevel.ReadCommitted
是。在这种情况下,事务需要在C代码中开始,您有以下选项:
- 使用
连接对象中的
事务
:
using (var conn = new SqlConnection(connString)) { conn.Open(); using (IDbTransaction tran = conn.BeginTransaction()) { try { // transactional code... using (SqlCommand cmd = conn.CreateCommand()) { // Loop the Insert operation here cmd.CommandText = "INSERT Operation"; cmd.Transaction = tran as SqlTransaction; cmd.ExecuteNonQuery(); } tran.Commit(); } catch(Exception ex) { tran.Rollback(); throw; } } }
- 使用隐式或显式环境事务
- 使用
(隐式)环境事务(在异常情况下是自动回滚)TransactionScope
- 使用
(显式)环境事务committeabletransaction
var tran = new CommittableTransaction(); using (var conn = new SqlConnection(connString)) { conn.Open(); try { conn.EnlistTransaction(tran); using (SqlCommand cmd = conn.CreateCommand()) { // Loop the Insert operation here cmd.CommandText = "INSERT Operation"; cmd.ExecuteNonQuery(); } tran.Commit(); } catch(Exception ex) { tran.Rollback(); throw; } }
- 使用
环境事务
,请记住,如果您打开多个连接,那么它将从本地事务升级到全局事务
,因此需要MSDTC
,这会影响性能
检查以下链接:
只有当所有插入/DML都发生在同一事务上下文中时,这两个(Sql Server,C#)才是相同的,因为插入是多次往返的。要使两者相同,就需要使用TVP
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions() {
IsolationLevel = IsolationLevel.ReadCommitted
}))
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
// Loop the Insert operation here
cmd.CommandText = "INSERT Operation";
cmd.ExecuteNonQuery();
}
}
scope.Complete();
}
var tran = new CommittableTransaction();
using (var conn = new SqlConnection(connString))
{
conn.Open();
try
{
conn.EnlistTransaction(tran);
using (SqlCommand cmd = conn.CreateCommand())
{
// Loop the Insert operation here
cmd.CommandText = "INSERT Operation";
cmd.ExecuteNonQuery();
}
tran.Commit();
}
catch(Exception ex)
{
tran.Rollback();
throw;
}
}