服务器恢复事务失败.处理步骤
本文关键字:处理 失败 恢复 事务 服务器 | 更新日期: 2023-09-27 18:15:51
我正在写一个webservice方法插入到2个表。下面是我的代码:
MLL_Result _paClient = new MLL_Result();
lock (thisLock)
{
using (SqlConnection connection = new SqlConnection(ConfigurationSettings.AppSettings["Main.ConnectionString"]))
{
connection.Open();
SqlTransaction transaction;
transaction = connection.BeginTransaction("SampleTransaction");
try
{
// Do some insert / update here
#region FIRST
Tbl_Patient patientObject = new Tbl_Patient();
string[] spID = sid.Split('-');
patientObject.PID = pid;
patientObject.SID = sid;
patientObject.Seq = spID[1];
patientObject.Address = address;
patientObject.Phone = phone;
_paClient.Insert(patientObject, connection, transaction);
#endregion
/////
#region LAST
if (_interClient.CheckExist(patientObject.PID) == 0)
{
Tbl_Inter inteObject = new Tbl_Inter();
inteObject.PID = patientObject.PID;
inteObject.Address = patientObject.Address;
inteObject.DateIN = patientObject.DateIN;
_paClient.Insert(inteObject, connection, transaction);
}
#endregion
}
transaction.Commit();
}
catch (Exception ex)
{
#region Catch Exception
//Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
//MessageBox.Show(" Message:" + ex.Message);
// Attempt to roll back the transaction.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
//Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
//MessageBox.Show(" Message:" + ex2.Message);
}
#endregion
}
}
当流量低时,它确实工作得很好。但是当流量高时,它会产生如下错误:
The server failed to resume the transaction Desc ... The transaction active in the session has been commited or aborted by another session.
请帮我解决这个问题,请:()和使用锁和事务这样的冲突吗??
有几件事引起了我的注意。
您可能有一个与事务相关的序列化问题,您在事务连接上插入一个值,然后检查您刚刚在另一个非事务连接上插入的值是否存在。如果事务隔离级别设置为"serializable",读操作将被阻塞,直到超时。
在任何情况下,对于任何类型的"稀缺"资源管理(在本例中是数据库事务)的最佳实践是晚获取和早发布。您希望在开始事务和提交事务(或回滚事务)之间花费尽可能少的时间和CPU周期。在事务打开的整个过程中,数据库服务器同步对资源的访问、表的锁定范围等。
所以你可以考虑在事务外部填充你的DTO,而不是在事务内部。
我假设_paClient
和_interClient
都是这个代码所在的任何类的成员变量?我看到你传递了一个连接到_paClient
,但没有传递到_interClient
,所以_interClient
不能参与与_paClient
相同的事务。_interClient
从哪里获得其数据库连接?如果_interClient正在启动自己的数据库连接,您正在使用的数据库是否充分支持每个客户端多个连接?在原始连接上启动事务后再启动新连接可能会破坏原始连接。我不知道你正在使用什么数据库,也不知道这种事情可能会在该数据库的驱动程序堆栈中导致什么样的行为。
这里真的需要lock (thisLock)
吗?一般来说,锁定对性能没有帮助。但如果有必要,那就有必要。
嵌套的try/catch可能是多余的。您将在调用堆栈的边缘进行异常处理和日志记录,以便在这里捕获故障,对吗?
对于实际的事务管理,我会考虑采用一种不同的结构,可能更像下面的重写代码。请注意,您可以保留显式回滚代码,让Transaction对象的Dispose()方法处理回滚,但该行为是特定于提供程序的(它与SQL Server正常工作),您可能无法100%依赖它。
Tbl_Patient patientObject = new Tbl_Patient();
string[] spID = sid.Split('-');
patientObject.PID = pid;
patientObject.SID = sid;
patientObject.Seq = spID[1];
patientObject.Address = address;
patientObject.Phone = phone;
Tbl_Inter inteObject = null;
// does this CheckExist function have to hit the database, or can it avoid that?
if (_interClient.CheckExist(patientObject.PID) == 0)
{
inteObject = new Tbl_Inter();
inteObject.PID = patientObject.PID;
inteObject.Address = patientObject.Address;
inteObject.DateIN = patientObject.DateIN;
}
using (var con = new SqlConnection(ConfigurationSettings.AppSettings["Main.ConnectionString"]))
{
con.Open();
using( var tx = con.BeginTransaction("SampleTransaction") )
{
try
{
_paClient.Insert(patientObject, con, tx);
if( null != inteObject )
{
_paClient.Insert(inteObject, con, tx);
}
tx.Commit();
}
catch( Exception ex )
{
try{ transaction.Rollback(); }
catch( Exception ex2 )
{
// lame that this is necessary if you're not using implicit rollback
// write to log, whatever...
}
throw; //re-throw the original exception w/call stack for logging by your global exception handler
}
}
}