SQL SERVER 死锁

iefus 2016-08-18 05:27:05
C# 用SQLHelper 更新一个表,报异常,死锁。

更新数据是一条一条更新的。

频率不是很高,最多的时候可能1s 两条。

我把里面的方法修改了下,加了事务,不会报死锁了,但是会报 cmd.Transaction.Rollback(); 空引用。
把这句注解掉,catch里面把异常抛出来,还是死锁的异常。

怎么解决呀


public static int ExecuteNonQueryTran(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
if (connection == null) throw new ArgumentNullException("connection");

// Create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
//Undo
cmd.CommandTimeout = 0;

bool mustCloseConnection = false;

connection.Open();

PrepareCommand(cmd, connection, connection.BeginTransaction(), commandType, commandText, commandParameters, out mustCloseConnection);

try
{
// Finally, execute the command
int retval = cmd.ExecuteNonQuery();

cmd.Transaction.Commit();

// Detach the SqlParameters from the command object, so they can be used again
cmd.Parameters.Clear();
if (mustCloseConnection)
connection.Close();
return retval;
}
catch(Exception e)
{
cmd.Transaction.Rollback();
return 0;
}
finally
{
connection.Close();
}

}
...全文
473 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
iefus 2016-08-23
  • 打赏
  • 举报
回复
引用 16 楼 redshiliu 的回复:
按道理来说即便是并发N各事务来更新同一条数据也不会出现死锁,而只是会挂起一些事务等待资源空闲,死锁一般出现的场景是两个或更多的资源相互争用才会出现。
是的啊,我这个就是单纯的更新一个table。一般就是更新一条数据。 1秒之内,收到两条更新同一条数据的事件时,就死锁。。。
hrex88888888888 2016-08-20
  • 打赏
  • 举报
回复
学习 。
iefus 2016-08-19
  • 打赏
  • 举报
回复
引用 7 楼 redshiliu 的回复:
如果是更新一个表的数据,按顺序执行理论上不应该出现死锁,空引用,你自己仔细调试看看到底是运行到哪一句才报错的,另外你的这个写法真正的很别扭。
参考的SQLHelper类的方法,只是加了个try 语句,把transaction 生成了
iefus 2016-08-19
  • 打赏
  • 举报
回复
引用 5 楼 sp1234 的回复:
另外你写的 cmd.Transaction 毫无意义,删除了这个多余的东西。SQL Server 默认会对每一个 sql 单独启动一个事务,用不着你显式的启动一个事务。 既然你产生了“cmd.Transaction 空引用”的错误,只是问题更多了,你怎么能误认为死锁不存在了呢? 你准确知道具体哪一个语句抛出异常了吗?编程调试中应该删除 try...catch,让调试器准确断点进入异常语句,开始调试。你写了 try...catch,相信你已经丧失了大部分调试能力,你报告的“cmd.Transaction.Rollback(); 空引用”这个说法根本不可信,你也贴出不出在异常时对相关的为 null 值的变量的调试(以及当时其它变量的调试)画面。你说的这个,很可能是自己编造的异常信息。
刚开始用的SQLHelper里面的方法,下面这个。最外层用DAL 调用这个方法。 DAL外边用try 捕捉,把异常信息存入log table。会发生死锁,才想到在这个方法里加个transaction
public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
    {
        if (connection == null) throw new ArgumentNullException("connection");

        // Create a command and prepare it for execution
        SqlCommand cmd = new SqlCommand();
        //Undo
        cmd.CommandTimeout = 0;
        bool mustCloseConnection = false;
        PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection);

        // Finally, execute the command
        int retval = cmd.ExecuteNonQuery();

        // Detach the SqlParameters from the command object, so they can be used again
        cmd.Parameters.Clear();
        if (mustCloseConnection)
            connection.Close();
        return retval;
    }
iefus 2016-08-19
  • 打赏
  • 举报
回复
引用 4 楼 sp1234 的回复:
你的所有 sql 语句平常单独执行时,可以确保在 1 秒内完成吗?你的程序是不是有一个很慢的 sql、或者一堆轮询执行的 sql 语句, 一直在滥用数据库?
可以的,现在是某个系统的数据发生了变化,会发送一个xml message 给我的web service。web service解析数据,调用我的exe ,插入DB。被更新的table,现在140多万条记录。每天也就增加2万多条记录。
xian_wwq 2016-08-19
  • 打赏
  • 举报
回复
是不是代码重入了? 按顺序执行,按道理不会死锁 建议数据库操作使用单独线程,避免到处连接,到处调用
redshiliu 2016-08-19
  • 打赏
  • 举报
回复
如果是更新一个表的数据,按顺序执行理论上不应该出现死锁,空引用,你自己仔细调试看看到底是运行到哪一句才报错的,另外你的这个写法真正的很别扭。
gengchenhui 2016-08-19
  • 打赏
  • 举报
回复
这个封装的有点奇怪啊。。。 理论上,应该是大概这样: using(trans=connection.BeginTransaction()) { SqlCommand cmd = new SqlCommand(); cmd.Transaction=trans;//这个可能要强制转换一下?忘了 //这个地方给cmd赋值,执行 trans.Commit(); }
  • 打赏
  • 举报
回复
另外你写的 cmd.Transaction 毫无意义,删除了这个多余的东西。SQL Server 默认会对每一个 sql 单独启动一个事务,用不着你显式的启动一个事务。 既然你产生了“cmd.Transaction 空引用”的错误,只是问题更多了,你怎么能误认为死锁不存在了呢? 你准确知道具体哪一个语句抛出异常了吗?编程调试中应该删除 try...catch,让调试器准确断点进入异常语句,开始调试。你写了 try...catch,相信你已经丧失了大部分调试能力,你报告的“cmd.Transaction.Rollback(); 空引用”这个说法根本不可信,你也贴出不出在异常时对相关的为 null 值的变量的调试(以及当时其它变量的调试)画面。你说的这个,很可能是自己编造的异常信息。
  • 打赏
  • 举报
回复
你的所有 sql 语句平常单独执行时,可以确保在 1 秒内完成吗?你的程序是不是有一个很慢的 sql、或者一堆轮询执行的 sql 语句, 一直在滥用数据库?
Justin-Liu 2016-08-19
  • 打赏
  • 举报
回复
取消所有static
iefus 2016-08-19
  • 打赏
  • 举报
回复
来个大神看下吧
redshiliu 2016-08-19
  • 打赏
  • 举报
回复
按道理来说即便是并发N各事务来更新同一条数据也不会出现死锁,而只是会挂起一些事务等待资源空闲,死锁一般出现的场景是两个或更多的资源相互争用才会出现。
iefus 2016-08-19
  • 打赏
  • 举报
回复
原因找到了,在同一秒内,会有两个更新同一条数据的请求过来。后来的那个死锁了。。。 webservice 先调用一个exe,更新一条数据,花费时间在1秒内, 然后webservice又掉起了 exe,再更新同一条数据。死锁。 还有一个问题没明白,第一次更新花费时间在1秒内,第二个 更新不会等一下么? 下面的代码不是让他一直等待么,怎么那么快就返回死锁了 cmd.CommandTimeout = 0;
iefus 2016-08-19
  • 打赏
  • 举报
回复
我调用SQLHelper原来的方法
  public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
    {
        if (connection == null) throw new ArgumentNullException("connection");

        // Create a command and prepare it for execution
        SqlCommand cmd = new SqlCommand();
        //Undo
        cmd.CommandTimeout = 0;
        bool mustCloseConnection = false;
        PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection);

        // Finally, execute the command
        int retval = cmd.ExecuteNonQuery();

        // Detach the SqlParameters from the command object, so they can be used again
        cmd.Parameters.Clear();
        if (mustCloseConnection)
            connection.Close();
        return retval;
    }
出现了下面的异常
System.Data.SqlClient.SqlException (0x80131904): 事务(进程 ID 221)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务。
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at SqlHelper.ExecuteNonQuery(SqlConnection connection, CommandType commandType, String commandText, SqlParameter[] commandParameters) in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\SQLHelper.cs:line 364
   at LotTrigger.MQLots_DAL.Update_MQLotTransactions_MoveOut_DAL(MQLots_BLL objBLL) in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\MQLots_DAL.cs:line 1173
   at LotTrigger.MQLots_BLL.Update_MQLotTransactions_MoveOut_BLL() in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\MQLots_BLL.cs:line 235
   at LotTrigger.Program.CheckMQData(MQLots_BLL objBLL, ILog log, Int32 mqDataId) in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\Program.cs:line 186
ClientConnectionId:807f373d-4661-4fa5-9516-728cb2327712
Error Number:1205,State:52,Class:13
风吹腚腚凉 2016-08-19
  • 打赏
  • 举报
回复
不清楚具体原因无法推断,建议你自己分析一下你自己的逻辑,从中找出死锁的原因。
正怒月神 2016-08-19
  • 打赏
  • 举报
回复
去掉static试试看呢。
iefus 2016-08-18
  • 打赏
  • 举报
回复
死锁的异常
System.Data.SqlClient.SqlException (0x80131904): 事务(进程 ID 283)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务。
   at SqlHelper.ExecuteNonQueryTran(SqlConnection connection, CommandType commandType, String commandText, SqlParameter[] commandParameters) in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\SQLHelper.cs:line 425
   at LotTrigger.MQLots_DAL.Update_MQLotTransactions_MoveOut_DAL(MQLots_BLL objBLL) in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\MQLots_DAL.cs:line 1173
   at LotTrigger.MQLots_BLL.Update_MQLotTransactions_MoveOut_BLL() in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\MQLots_BLL.cs:line 235
   at LotTrigger.Program.CheckMQData(MQLots_BLL objBLL, ILog log, Int32 mqDataId) in E:\SVN\system\sourcecode\MPS\MPS_Trigger\LotTrigger\LotTrigger\LotTrigger\Program.cs:line 186
ClientConnectionId:0b3e71e3-6770-4c9d-ab70-903863118b2c
Error Number:1205,State:52,Class:13
加了事务之后的异常
System.NullReferenceException: Object reference not set to an instance of an object.
   at SqlHelper.ExecuteNonQueryTran(SqlConnection connection, CommandType commandType, String commandText, SqlParameter[] commandParameters) in 。。。\SQLHelper.cs:line 415

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧