AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 344227
Accepted
SE1986
SE1986
Asked: 2024-12-16 20:00:07 +0800 CST2024-12-16 20:00:07 +0800 CST 2024-12-16 20:00:07 +0800 CST

RAISERROR / THROW 和 sp_start_job 终止行为

  • 772

假设以下 SQL Server 代理作业

USE [msdb]
GO


BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0

IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

END

DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'Do Nothing', 
        @enabled=1, 
        @notify_level_eventlog=0, 
        @notify_level_email=0, 
        @notify_level_netsend=0, 
        @notify_level_page=0, 
        @delete_level=0, 
        @description=N'No description available.', 
        @category_name=N'[Uncategorized (Local)]', 
        @owner_login_name=N'Me', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Wait', 
        @step_id=1, 
        @cmdexec_success_code=0, 
        @on_success_action=1, 
        @on_success_step_id=0, 
        @on_fail_action=2, 
        @on_fail_step_id=0, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'TSQL', 
        @command=N'WAITFOR DELAY ''00:00:10''', 
        @database_name=N'master', 
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO

以及以下调用代码

EXEC msdb.dbo.sp_start_job @job_name = 'Do nothing' -- waits for 10 seconds
WAITFOR DELAY '00:00:05'
EXEC msdb.dbo.sp_start_job @job_name = 'Do nothing' -- fails, job still running
WAITFOR DELAY '00:00:10'
EXEC msdb.dbo.sp_start_job @job_name = 'Do nothing' -- should succeed

我收到以下错误:

Job 'Do nothing' started successfully. Msg 22022, Level 16, State 1, Line 25 SQLServerAgent Error: Request to run job Do Nothing (from User Me) refused because the job is already running from a request by User Me. Job 'Do nothing' started successfully.

因此我们可以看到第二次sp_start_job调用失败,因为作业仍在运行,然后 SQL Server 继续执行

故障级别为 16,当我执行以下操作时

PRINT 'hello'
    RAISERROR ('error',16,1)
PRINT 'hello'

我得到了相同的“失败并继续”行为

hello
Msg 50000, Level 16, State 1, Line 50
error
hello

但是,如果我执行以下操作,也会引发 16 级错误,则不会运行第二次打印

PRINT 'hello'
    ;THROW 51000, 'error', 1;
PRINT 'hello'

hello
Msg 51000, Level 16, State 1, Line 50
error

THROW状态的文档

THROW 语句中发生的任何错误都会导致语句批处理终止。

RAISERROR状态的文档

如果运行 RAISERROR,则会将错误返回给调用者:超出任何 TRY 块的范围。在 TRY 块中严重性为 10 或更低。严重性为 20 或更高,终止数据库连接。

我的问题是,是否sp_start_job使用 RAISERROR 而不是 throw - 我已经研究过定义,但找不到任何地方

sql-server
  • 1 1 个回答
  • 66 Views

1 个回答

  • Voted
  1. Best Answer
    Charlieface
    2024-12-16T20:39:46+08:002024-12-16T20:39:46+08:00

    是的,它确实使用了RAISERROR,至少在我能看到的代码部分是这样。还有一些内部使用的扩展程序,我们没有这些程序的源代码,但我怀疑这里也会这样。

    您应该使用BEGIN CATCH来捕获此类错误,因为即使是 也RAISERROR不会终止执行。SET XACT_ABORTON

    BEGIN TRY
        EXEC msdb.dbo.sp_start_job @job_name = 'Do nothing'; -- waits for 10 seconds
        WAITFOR DELAY '00:00:05';
        EXEC msdb.dbo.sp_start_job @job_name = 'Do nothing'; -- fails, job still running
        WAITFOR DELAY '00:00:10';
        EXEC msdb.dbo.sp_start_job @job_name = 'Do nothing'; -- should succeed
    END TRY
    BEGIN CATCH
        PRINT 'caught';
    END CATCH;
    

    以下是 的完整定义sp_start_job,您可以看到它RAISERROR在很多地方使用。您可以使用 获得此定义select definition from msdb.sys.sql_modules where object_id = object_id('msdb..sp_start_job')。

    CREATE PROCEDURE sp_start_job
      @job_name    sysname          = NULL,
      @job_id      UNIQUEIDENTIFIER = NULL,
      @error_flag  INT              = 1,    -- Set to 0 to suppress the error from sp_sqlagent_notify if SQLServerAgent is not running
      @server_name sysname          = NULL, -- The specific target server to start the [multi-server] job on
      @step_name   sysname          = NULL, -- The name of the job step to start execution with [for use with a local job only]
      @output_flag INT              = 1     -- Set to 0 to suppress the success message
    AS
    BEGIN
      DECLARE @job_id_as_char VARCHAR(36)
      DECLARE @retval         INT
      DECLARE @step_id        INT
      DECLARE @job_owner_sid  VARBINARY(85)
    
      SET NOCOUNT ON
    
      -- Remove any leading/trailing spaces from parameters
      SELECT @job_name    = LTRIM(RTRIM(@job_name))
      SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
      SELECT @step_name   = LTRIM(RTRIM(@step_name))
    
      -- Turn [nullable] empty string parameters into NULLs
      IF (@job_name = N'')    SELECT @job_name = NULL
      IF (@server_name = N'') SELECT @server_name = NULL
      IF (@step_name = N'')   SELECT @step_name = NULL
    
      EXECUTE @retval = sp_verify_job_identifiers '@job_name',
                                                  '@job_id',
                                                   @job_name OUTPUT,
                                                   @job_id   OUTPUT,
                                                   @owner_sid = @job_owner_sid OUTPUT
      IF (@retval <> 0)
        RETURN(1) -- Failure
    
      -- Check permissions beyond what's checked by the sysjobs_view
      -- SQLAgentReader role can see all jobs but
      -- cannot start/stop jobs they do not own
      IF (@job_owner_sid <> SUSER_SID()                      -- does not own the job
         AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0)     -- is not sysadmin
         AND (ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) = 0))  -- is not SQLAgentOperatorRole
      BEGIN
       RAISERROR(14393, -1, -1);  
       RETURN(1) -- Failure
      END
    
      IF (NOT EXISTS (SELECT *
                      FROM msdb.dbo.sysjobservers
                      WHERE (job_id = @job_id)))
      BEGIN
        SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
        RAISERROR(14256, -1, -1, @job_name, @job_id_as_char)
        RETURN(1) -- Failure
      END
    
      IF (EXISTS (SELECT *
                  FROM msdb.dbo.sysjobservers
                  WHERE (job_id = @job_id)
                    AND (server_id = 0)))
      BEGIN
        -- The job is local, so start (run) the job locally
    
        -- Check the step name (if supplied)
        IF (@step_name IS NOT NULL)
        BEGIN
          SELECT @step_id = step_id
          FROM msdb.dbo.sysjobsteps
          WHERE (step_name = @step_name)
            AND (job_id = @job_id)
    
          IF (@step_id IS NULL)
          BEGIN
            RAISERROR(14262, -1, -1, '@step_name', @step_name)
            RETURN(1) -- Failure
          END
        END
    
        EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
                                                      @job_id      = @job_id,
                                                      @schedule_id = @step_id, -- This is the start step
                                                      @action_type = N'S',
                                                      @error_flag  = @error_flag
        IF ((@retval = 0) AND (@output_flag = 1))
          RAISERROR(14243, 0, 1, @job_name)
      END
      ELSE
      BEGIN
        -- The job is a multi-server job
    
          -- Only sysadmin can start multi-server job
          IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
          BEGIN
             RAISERROR(14397, -1, -1);
             RETURN(1) -- Failure
          END            
    
        -- Check target server name (if any)
        IF (@server_name IS NOT NULL)
        BEGIN
          IF (NOT EXISTS (SELECT *
                          FROM msdb.dbo.systargetservers
                          WHERE (UPPER(server_name) = @server_name)))
          BEGIN
            RAISERROR(14262, -1, -1, '@server_name', @server_name)
            RETURN(1) -- Failure
          END
        END
    
        -- Re-post the job if it's an auto-delete job
        IF ((SELECT delete_level
             FROM msdb.dbo.sysjobs
             WHERE (job_id = @job_id)) <> 0)
          EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name
    
        -- Post start instruction(s)
        EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'START', 'JOB', @job_id, @server_name
      END
    
      RETURN(@retval) -- 0 means success
    END
    
    • 4

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve