SQLSERVE事务编写没问题但出现锁表解决思路参考(类似于EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 0,当前计数 = 1)

错误提示:

EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 0,当前计数 = 1。

错误原因:
BEGIN 看成计数开始点
COMMIT 和R OLLBACK 看成计数结束点
每个计数 开始点 和 结束点 要成对匹配

情况分析

1. BEGIN 和 COMMIT 中间有RETURN的存在 , 后面的COMMIT(ROLLBACK)不会被执行,所以数目不匹配

Select @rval = 0
BEGIN TRANSACTION
 
    Insert Into USERS(name , age) VALUES( @name , @age)
    if @@error <> 0
    BEGIN
        Select @rval = -1
        return -- 错误示例:这里返回后,下面的代码不会被执行,最后的COMMIT会引起不匹配
    END
 
    Insert Into company(address , tel) values(@address , @tel)
    if @@error <> 0
    BEGIN
        Select @rval = -2
        return -- 错误示例:这里返回后,下面的代码不会被执行,最后的COMMIT会引起不匹配
    END
COMMIT TRANSACTION

2.COMMIT前有ROLLBACK , 执行了ROLLBACK 后不使用RETURN,继续执行后面代码中如果有COMMIT数目也不匹配。

Select @rval = 0
BEGIN TRANSACTION
 
    Insert Into USERS(name , age) VALUES( @name , @age)
    if @@error <> 0
    BEGIN
        Select @rval = -1       
    END
 
    Insert Into company(address , tel) values(@address , @tel)
    if @@error <> 0
    BEGIN
        Select @rval = -2
        ROLLBACK TRANSACTION
        return -- 因为上面一行代码使用了ROLLBACK,已经结束了和前面BEGIN的匹配,所以继续执行下去的COMMIT会造成不匹配,所以这里必须使用return 不执行最后的COMMIT
    END
COMMIT TRANSACTION

解决方法:

  1. 只有 BEGIN 与 COMMIT , 中间没有ROLLBACK,那么BEGIN和COMMIT之间不能用 RETURN

  2. 如果使用了ROLLBACK回滚事务,要检查BEGIN的匹配数

上面两种情况是参考https://blog.csdn.net/s_156/article/details/126627444该篇文章的,我懒得写了,注意讲述下面这种

其他情况

情况
存储过程中如 UPDATE语句中SET时某个字段名打错,他执行了这个事务,也会这么提示错误信息,但是现在执行SELECT 该事务中某个表且不带WITH(NOLOCK)时还不会卡住,当你修改这个错误的字段名时,再执行存储过程中的事务时,显示执行完成,但去执行SELECT 该事务中某个表且不带WITH(NOLOCK)时会直接卡住

消息 207,级别 16,状态 1,过程 p_wlck_inport_yd_ydsh_cs,行 44 [批起始行 2]
列名 'shnhe_czydm' 无效。
消息 266,级别 16,状态 2,过程 p_wlck_inport_yd_ydsh_cs,行 44 [批起始行 2]
EXECUTE 后的事务计数指示 BEGINCOMMIT 语句的数目不匹配。上一计数 = 0,当前计数 = 1

原因
因为之前执行了报错,而且事务未提交,再次执行时就会导致事务计数不匹配,然后有一个就会一直提交不了,才导致就算执行成功了,通过SELECT WITH(NOLOCK) 查询结果,是和预想一致的,但事务就是没提交。(就相当于写了两个BEGIN,但是END只有一个;第一次执行了一个BEGIN但因为中途报错了,所以没有END接上,后面又来一个BEGIN END然后就导致有缺漏)

解决

查看sqlserver被锁的表以及如何解锁

查看被锁表:

select   request_session_id   spid,OBJECT_NAME(resource_associated_entity_id) tableName   

from   sys.dm_tran_locks where resource_type='OBJECT'

找到事务中表对应的spid
 

spid   锁表进程 

tableName   被锁表名

 

解锁:

declare @spid  int 

Set @spid  = 57 --锁表进程(根据上面查出来的)

declare @sql varchar(1000)

set @sql='kill '+cast(@spid  as varchar)

exec(@sql)

这种情况一般不会出现,出现解决方法如上,因为这种是人为导致,修改存储过程时,存储过程也没有检测到导致,写BEGIN TRY BEGIN CATCH并不能捕获处理到

另一种解决方法,不推荐

BEGIN TRY
BEGIN TRANSACTION
  ALTER TABLE [Items] ADD tagID [uniqueidentifier] NULL

  MERGE INTO
    Items AS target
  USING
    Tags AS t ON t.tag = target.tag
  WHEN MATCHED THEN
    UPDATE SET target.tagID = t.id;
COMMIT
END TRY
BEGIN CATCH
  IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION
END CATCH
GO
--SQL Server 尝试编译批处理中的所有语句。如果表不存在,则语句的编译会被推迟,但对于缺失的列没有延迟编译。
BEGIN TRY
BEGIN TRANSACTION
  ALTER TABLE [Items] ADD tagID [uniqueidentifier] NULL
  EXEC('
  MERGE INTO
    Items AS target
  USING
    Tags AS t ON t.tag = target.tag
  WHEN MATCHED THEN
    UPDATE SET target.tagID = t.id;
 ')
COMMIT
END TRY
BEGIN CATCH
  IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION
END CATCH
GO

你可能感兴趣的:(sql笔记,数据库,java,服务器)