SQL Server 存储过程开发手册

SQL Server 存储过程开发手册(更新版)

根据要求,重新整理并加入了事务控制、异常日志记录和返回状态码的设计。以下是详细说明:


1. 总则

1.1 目标

本手册旨在为 SQL Server 存储过程的编写提供一套完整的规范,确保系统的事务控制、异常处理、日志记录和状态码返回清晰明确,优化数据一致性、系统稳定性和性能。


2. 事务控制与层次化设计

2.1 事务控制原则

根据业务的需求和事务的粒度,存储过程应分为不同的层次,每个层次的事务控制和异常处理策略不同,具体如下表所示:

层次 控制事务 记录异常日志 返回状态码
主流程 (Main)
子事务 (SubTx)
功能性操作 (Func) 可选
  • 主流程 (Main)

    • 不控制事务,负责协调和调用子事务或功能性操作。

    • 记录异常日志,捕获并输出错误信息。

    • 返回状态码,以通知调用方执行状态(成功或失败)。

  • 子事务 (SubTx)

    • 控制事务,开始和提交或回滚事务。

    • 记录异常日志,在发生异常时捕获并输出错误信息。

    • 返回状态码,标识事务是否成功完成。

  • 功能性操作 (Func)

    • 不控制事务,通常是读取操作或不涉及数据修改的辅助功能。

    • 不记录异常日志(除非必要),通常这些操作在主流程中捕获异常。

    • 返回状态码可选,根据具体业务需要决定是否返回。


3. 存储过程命名规范

存储过程命名应该遵循以下结构,便于识别和维护:

复制代码
proc_领域_子领域_类型
  • 领域 (Domain):表示存储过程所属的业务领域,如订单、用户、商品等。

  • 子领域 (SubDomain):表示存储过程在领域中的具体细分模块,如发货、支付、库存等。

  • 类型 (Type):表示存储过程的类型,分为三种类型:

    • Main:主流程,负责协调其他子事务和功能性操作。

    • SubTx:子事务,负责数据更新和事务控制。

    • Func:功能性操作,通常是查询或计算操作。

3.1 示例命名

  • proc_Order_Shipment_SubTx:表示"订单"领域中的"发货"子领域的子事务,涉及事务控制。

  • proc_Order_Payment_Main:表示"订单"领域中的"支付"子领域的主流程,负责调用其他子事务。

  • proc_Inventory_Check_Func:表示"库存"领域中的"检查"功能,通常用于查询操作,不涉及事务控制。


4. 存储过程设计与事务控制

4.1 主流程存储过程

主流程存储过程不涉及事务控制,它的职责是调用子事务和功能性操作,并记录异常日志和返回执行状态码。

复制代码
CREATE PROCEDURE proc_Order_Shipment_Main
    @OrderId INT,
    @code INT output,
    @msg varchar(500) output
AS
BEGIN
    BEGIN TRY
        -- 调用子事务,子事务控制事务
        EXEC proc_Order_Shipment_SubTx @OrderId, @code,@msg  ;
        if(@code!=200){
          -- 记录失败原因,处理失败带来的影响
          return
        }

        -- 调用功能性操作(如果需要)
        EXEC proc_Inventory_Check_Func @OrderId, @code,@msg ;
        if(@code!=200){
          -- 记录失败原因,处理失败带来的影响
          return
        }
        -- 返回成功状态码
        set @code=200
    END TRY
    BEGIN CATCH
        -- 捕获并记录异常日志
        PRINT 'Error in proc_Order_Shipment_Main: ' + ERROR_MESSAGE();
        -- 返回失败状态码
        RETURN 1; -- 状态码:1 表示失败
    END CATCH
END;

4.2 子事务存储过程

子事务存储过程负责控制事务,它需要开始、提交和回滚事务,并在发生异常时记录日志和返回状态码。

复制代码
CREATE PROCEDURE proc_Order_Shipment_SubTx
    @OrderId INT,
    @code INT output,
    @msg varchar(500) output
AS
BEGIN
    -- 开始事务
    BEGIN TRANSACTION;

    BEGIN TRY
        -- 订单发货相关的数据库操作
        UPDATE dbo.Order
        SET ShipmentStatus = 'Shipped'
        WHERE OrderId = @OrderId;

        -- 提交事务
        COMMIT TRANSACTION;

        -- 返回成功状态码
        RETURN 0; -- 状态码:0 表示成功
    END TRY
    BEGIN CATCH
        -- 发生错误时回滚事务
        ROLLBACK TRANSACTION;

        -- 记录异常日志
        PRINT 'Error in proc_Order_Shipment_SubTx: ' + ERROR_MESSAGE();

        -- 返回失败状态码
        RETURN 1; -- 状态码:1 表示失败
    END CATCH
END;

4.3 功能性操作存储过程

功能性操作通常是只执行查询或计算,不涉及数据修改,因此不控制事务。日志记录和状态码返回可选,具体业务需求决定。

复制代码
CREATE PROCEDURE proc_Inventory_Check_Func
    @OrderId INT,
    @code INT output,
    @msg varchar(500) output
AS
BEGIN
    -- 查询操作,检查库存
    SELECT ProductId, AvailableStock
    FROM dbo.Inventory
    WHERE ProductId IN (SELECT ProductId FROM dbo.OrderItems WHERE OrderId = @OrderId);
END;

5. 错误处理与日志记录

5.1 错误处理

  • 主流程:主流程存储过程捕获所有子事务和功能性操作中的异常,但不控制事务回滚。它应当记录异常日志,并返回相应的状态码(通常是 0 或 1)。

  • 子事务 :子事务存储过程必须通过 BEGIN TRYBEGIN CATCH 语句来捕获异常,并在异常发生时回滚事务。所有异常都应该记录日志,并返回状态码,标识事务是否成功。

  • 功能性操作:功能性操作通常不捕获异常,也不记录日志,异常处理依赖于主流程。

5.2 异常日志记录

所有的异常都应通过日志记录下来,方便后期排查和优化。可以使用 PRINTRAISEERROR 语句来记录错误消息。

复制代码
BEGIN CATCH
    PRINT 'Error: ' + ERROR_MESSAGE();
    -- 或者使用 RAISEERROR 记录更详细的日志
    -- RAISEERROR('Error in procedure: %s', 16, 1, ERROR_MESSAGE());
    THROW;
END CATCH

6. 返回状态码

每个存储过程在执行完毕后应返回一个状态码,状态码通常为:

  • 0:表示操作成功。

  • 1:表示操作失败(可根据需要扩展更多状态码,表示不同类型的错误)。

返回状态码用于调用方判断存储过程执行是否成功,并做相应的处理。


7. 性能优化与锁争用

  • 避免长事务:事务内只包含必要的数据库操作,避免外部接口或延时任务的调用。

  • 批量处理:对于需要更新大量数据的操作,尽量使用批量处理,减少事务锁的持有时间。

  • 索引优化:确保数据库表有适当的索引,以加速查询和数据操作。


8. 审查与监控

8.1 代码审查标准

  • 确保每个存储过程的事务控制符合规范。

  • 确保异常处理机制完备,并且日志记录充分。

  • 确保存储过程有清晰的返回状态码,便于系统监控。

8.2 监控与日志

  • 监控长时间运行的事务,避免事务阻塞。

  • 配置合适的告警机制,及时捕获死锁或其他异常。


总结

  • 通过分层设计,每个存储过程的责任清晰,主流程不控制事务,子事务控制事务,功能性操作不涉及事务管理。

  • 存储过程命名规则统一,便于后续维护和扩展。

  • 错误处理和日志记录是保证系统稳定性的关键,每个存储过程都应有明确的异常处理和日志记录机制。

相关推荐
星星点点洲3 分钟前
【缓存与数据库结合方案】伪从技术 vs 直接同步/MQ方案的深度对比
数据库·缓存
努力奋斗的小杨6 分钟前
学习MySQL的第十二天
数据库·笔记·学习·mysql·navicat
枫叶20001 小时前
OceanBase数据库-学习笔记1-概论
数据库·笔记·学习·oceanbase
仲夏plus1 小时前
MySQL:慢SQL索引优化-使用explain/analyze进行耗时分析的方法
数据库
tcoding1 小时前
《MySQL 技术内幕-innoDB 存储引擎》笔记
数据库·笔记·mysql
Edward.W2 小时前
如何有效防止 SQL 注入攻击?
数据库·sql
好想有猫猫2 小时前
【Redis】服务端高并发分布式结构演进之路
数据库·c++·redis·分布式·缓存
桥Dopey3 小时前
关系型数据库PostgreSQL for Mac 保姆级使用教程
数据库·postgresql
@_猿来如此3 小时前
Django 实现电影推荐系统:从搭建到功能完善(附源码)
数据库·后端·python·django