我如何跨多个方法使用 Sql Transaction
How do i use SqlTransaction across multipe methods
假设我们有一个可以删除的对象 A 和一个持有来自 A 的 forendkey 的对象 B
如果你想删除A,你必须先从B删除forendkey然后你可以删除A但是如果出现问题应该回滚但是我也想使用从B独立删除forendkey但是目前我不知道如何实现这个
我目前的想法:
public void DeleteA(Object a)
{
using (SqlConnection con = new SqlConnection())
{
con.open();
using (SqlTransaction tr = con.BeginTransaction())
{
try
{
DeleteAfromAllB(a, con, tr);
using (SqlCommand cmd = new SqlCommand("STP_A_Delete", con))
{
cmd.Transaction = tr;
// some parameters
// some sort of Execute
// e.g.: cmd.ExecuteNonQuery();
}
tr.Commit();
}
catch (SqlException ex)
{
//ExceptionHandling
}
}
}
}
private void DeleteAfromAllB(Object a, SqlConnection con, SqlTransaction tr)
{
try
{
using (SqlCommand cmd = new SqlCommand("STP_B_Delete_Referenc_To_A", con))
{
cmd.Transaction = tr;
// some parameters
// some sort of Execute
// e.g.: cmd.ExecuteNonQuery();
}
}
catch (SqlException ex)
{
//ExceptionHandling
}
}
public void DeleteAfromAllB(Object a)
{
using (SqlConnection con = new SqlConnection())
{
con.open();
using (SqlTransaction tr = con.BeginTransaction())
{
DeleteAfromAllB(a,con,tr);
tr.Commit();
}
}
}
但是你可以看到这很丑
来电
public void DeleteAfromAllB(Object a)
不需要传递 SqlConnection,因为您可以从 tr.Connection 中引用。所以你只需要 SqlTransaction 作为参数。因此,对于您最初的问题,是的,我认为传入 SqlTransaction 是可行的方法。我个人更喜欢这种方式,因为您可以轻松地跟踪调用堆栈/交易范围(即交易started/finished)的位置。
另一种选择是使用 TransactionScope。
例如
private void DeleteAfromAllB(Object a)
{
using (var con = new SqlConnection())
{
con.open();
using (var cmd = new SqlCommand("STP_B_Delete_Referenc_To_A", con))
{
// some parameters
// some sort of Execute
// e.g.: cmd.ExecuteNonQuery();
}
}
}
public void DeleteAfromAllB_TopLevel(Object a)
{
using (var scope = new TransactionScope())
{
try
{
DeleteAfromAllB(a);
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
catch (Exception)
{
//ExceptionHandling
}
}
}
假设我们有一个可以删除的对象 A 和一个持有来自 A 的 forendkey 的对象 B
如果你想删除A,你必须先从B删除forendkey然后你可以删除A但是如果出现问题应该回滚但是我也想使用从B独立删除forendkey但是目前我不知道如何实现这个
我目前的想法:
public void DeleteA(Object a)
{
using (SqlConnection con = new SqlConnection())
{
con.open();
using (SqlTransaction tr = con.BeginTransaction())
{
try
{
DeleteAfromAllB(a, con, tr);
using (SqlCommand cmd = new SqlCommand("STP_A_Delete", con))
{
cmd.Transaction = tr;
// some parameters
// some sort of Execute
// e.g.: cmd.ExecuteNonQuery();
}
tr.Commit();
}
catch (SqlException ex)
{
//ExceptionHandling
}
}
}
}
private void DeleteAfromAllB(Object a, SqlConnection con, SqlTransaction tr)
{
try
{
using (SqlCommand cmd = new SqlCommand("STP_B_Delete_Referenc_To_A", con))
{
cmd.Transaction = tr;
// some parameters
// some sort of Execute
// e.g.: cmd.ExecuteNonQuery();
}
}
catch (SqlException ex)
{
//ExceptionHandling
}
}
public void DeleteAfromAllB(Object a)
{
using (SqlConnection con = new SqlConnection())
{
con.open();
using (SqlTransaction tr = con.BeginTransaction())
{
DeleteAfromAllB(a,con,tr);
tr.Commit();
}
}
}
但是你可以看到这很丑
来电
public void DeleteAfromAllB(Object a)
不需要传递 SqlConnection,因为您可以从 tr.Connection 中引用。所以你只需要 SqlTransaction 作为参数。因此,对于您最初的问题,是的,我认为传入 SqlTransaction 是可行的方法。我个人更喜欢这种方式,因为您可以轻松地跟踪调用堆栈/交易范围(即交易started/finished)的位置。
另一种选择是使用 TransactionScope。
例如
private void DeleteAfromAllB(Object a)
{
using (var con = new SqlConnection())
{
con.open();
using (var cmd = new SqlCommand("STP_B_Delete_Referenc_To_A", con))
{
// some parameters
// some sort of Execute
// e.g.: cmd.ExecuteNonQuery();
}
}
}
public void DeleteAfromAllB_TopLevel(Object a)
{
using (var scope = new TransactionScope())
{
try
{
DeleteAfromAllB(a);
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
catch (Exception)
{
//ExceptionHandling
}
}
}