我有一个简单地执行存储过程的 SQL 作业。每天早上,当作业尝试运行时,我都会收到以下错误:
当前事务无法提交,并且无法支持写入日志文件的操作。
当我继续尝试重新开始工作时,它一直给我同样的错误。但是,如果我只执行存储过程而不使用 Job,它就可以正常工作。
这是真正非常棘手的部分。如果我只是运行存储过程,取消它,然后运行作业,那么作业就可以正常工作了。
有没有人遇到过这个相当独特的问题或有任何想法可能导致它?
我有一个简单地执行存储过程的 SQL 作业。每天早上,当作业尝试运行时,我都会收到以下错误:
当前事务无法提交,并且无法支持写入日志文件的操作。
当我继续尝试重新开始工作时,它一直给我同样的错误。但是,如果我只执行存储过程而不使用 Job,它就可以正常工作。
这是真正非常棘手的部分。如果我只是运行存储过程,取消它,然后运行作业,那么作业就可以正常工作了。
有没有人遇到过这个相当独特的问题或有任何想法可能导致它?
此错误表明您正在尝试在注定的事务期间执行记录操作。如果您忽略 -1 的XACT_STATE值,这只会发生在 BEGIN CATCH 块中:
当前请求有一个活动的用户事务,但发生了一个错误,导致该事务被归类为不可提交事务。请求无法提交事务或回滚到保存点;它只能请求事务的完全回滚。该请求在回滚事务之前不能执行任何写操作。该请求只能执行读取操作,直到它回滚事务。事务回滚后,请求可以执行读取和写入操作,并且可以开始新事务。
您尝试执行此操作的事实仅表明您的异常处理存在代码问题(换句话说,您的过程有问题)。我最近写了一篇关于使用 BEGIN TRY/BEGIN CATCH 的程序模板的博客,您可以将其用作修复程序的起点。Erland Sommarskog 有一篇关于 Transact-SQL 错误处理的著名文章,但这并没有太深入地介绍 BEGIN TRY/BEGIN CATCH。
通过适当的错误处理,您可以找出发生的原始错误并导致您的 CATCH 块首先被执行。由于您提到手动运行该过程不会导致任何问题,因此问题可能是 SQL 代理作业和您的手动执行之间的上下文差异。我无法在没有任何数据的情况下诊断问题,但我猜测最可能的原因是安全上下文的差异(即代理登录缺少您自己的登录所拥有的某些权限)。
我在不同的条件下遇到了这个错误,我想出了一个简短的复制路径(缺少软件缺陷IF XACT_STATE() != 1 ROLLBACK
):
-- prepare SP
IF OBJECT_ID(N'ShortReplicationPath',N'P') IS NOT NULL DROP PROCEDURE dbo.ShortReplicationPath
GO
CREATE PROCEDURE dbo.ShortReplicationPath
AS
BEGIN
BEGIN TRY
insert #TempTabDateTime (ValidFrom) Values ('date')
END TRY
BEGIN CATCH
PRINT ERROR_NUMBER(); PRINT ERROR_MESSAGE();
INSERT INTO #TempTabVarChar
( Text )
VALUES ( 'abcdefg' )
END CATCH
END
GO
-- Execute test:
IF OBJECT_ID ('TEMPDB..#TempTabDateTime') IS NOT NULL drop table #TempTabDateTime
create table #TempTabDateTime (ValidFrom DATETIME)
IF OBJECT_ID ('TEMPDB..#TempTabVarChar') IS NOT NULL drop table #TempTabVarChar
create table #TempTabVarChar (Text VarChar(MAX))
BEGIN TRANSACTION
EXEC dbo.ShortReplicationPath
ROLLBACK
GO