错误提示:
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
解决方法:
-
只有 BEGIN 与 COMMIT , 中间没有ROLLBACK,那么BEGIN和COMMIT之间不能用 RETURN
-
如果使用了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 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 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