当前位置: 代码迷 >> Sql Server >> 一个简单的存储过程产生死锁解决方案
  详细解决方案

一个简单的存储过程产生死锁解决方案

热度:73   发布时间:2016-04-27 17:58:58.0
一个简单的存储过程产生死锁
由于系统从Oracle数据库迁移成MsSQL,数据表的主键由程序控制产生,不想过多的改程序,于是我把所有表的主键保存在一个数据表里,表结构很简单: 
create table my_seq( 
  sequence_name varchar(50) not null, 
  sequence_value int(4) 



自定义存储过程如下: 

SQL code 
CREATE PROCEDURE GET_NEXTVAL
 
  @sequence_name varchar(200),
  @sequence_value INT output

AS
  BEGIN 
  -- DECLARE @sequence_value INT;
  SET NOCOUNT ON
  set @sequence_value = -1;
   
  begin TRANSACTION 
  update my_seq 
  SET sequence_value=sequence_value+1 
  WHERE [email protected]_name ;
  select @sequence_value=sequence_value from my_seq WHERE [email protected]_name ;
  COMMIT TRANSACTION 
   
  SET NOCOUNT OFF

  RETURN @sequence_value
  END
GO




存储过程做的事主要是:把键值加1后,马上更新数据库里的数据,最后返回处理后的下一数值. 

应用系统运行一段时间会出现如下异常: 
org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{call dbo.GET_NEXTVAL(?, ?)}]; SQL state [40001]; error code [1205]; [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]事务(进程 ID 58)与另一个进程已被死锁在 lock 资源上,且该事务已被选作死锁牺牲品。请重新运行该事务。; nested exception is java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]事务(进程 ID 58)与另一个进程已被死锁在 lock 资源上,且该事务已被选作死锁牺牲品。请重新运行该事务。 
java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]事务(进程 ID 58)与另一个进程已被死锁在 lock 资源上,且该事务已被选作死锁牺牲品。请重新运行该事务。 


网络上找到很多类似这样的问题,但我还是没有找到解决的办法.

------解决方案--------------------
感觉是事务和事务冲突导致的锁,这样你在这里加上一句;
SQL code
CREATE PROCEDURE  GET_NEXTVAL     @sequence_name  varchar(200),     @sequence_value INT output AS     BEGIN     -- DECLARE @sequence_value INT;     SET NOCOUNT ON     set @sequence_value = -1;     wait delay '00:00:00.1'           begin  TRANSACTION       update my_seq(rowlock)           SET  sequence_value=sequence_value+1             WHERE  [email protected]_name ;       select  @sequence_value=sequence_value from my_seq(nolock)          WHERE  [email protected]_name ;     COMMIT  TRANSACTION           SET NOCOUNT OFF     RETURN @sequence_value     END GO
------解决方案--------------------
探讨
先试下arrow_gx的方法,不过"select 使用 nolock"我担心会读脏数据.

------解决方案--------------------
这是一个并发性的问题,不应该仅仅从解决死锁这个角度考虑,否则即便暂时解决了死锁,可能也会出现其他的比如数据错误
我认为如果是应该再调用这个过程的代码加控制,每一个时刻保证对一个表(sequence_name ),只能有一个进程访问,不通表才能同时访问
或者对每个事务设置优先级,不过性能可能不如前者了
------解决方案--------------------
这么简单的过程也能死锁?不用强制什么锁吧
------解决方案--------------------
可以提高一下效率
update my_seq 
SET @sequence_value = sequence_value+1,sequence_value=sequence_value+1 
WHERE [email protected]_name ; 

产生锁的话,显然是你运行此存储过程太频繁了,有些程序不是你想不要多改就能不改的
当然的设计显然是自己在制造瓶颈!
  相关解决方案