后端开发:SQL 存储过程的错误处理

后端开发:SQL 存储过程的错误处理

关键词:SQL存储过程、错误处理、TRY-CATCH、事务管理、错误日志、数据库开发、异常处理

摘要:本文深入探讨SQL存储过程中的错误处理机制,从基础概念到高级应用全面覆盖。文章首先介绍存储过程错误处理的必要性,然后详细解析SQL Server和MySQL等主流数据库的错误处理实现方式,包括TRY-CATCH块、错误函数和自定义错误。接着通过实际代码示例展示如何构建健壮的存储过程,包括事务管理、错误日志记录和嵌套存储过程的错误处理策略。最后,文章讨论性能考量、最佳实践和未来发展趋势,为数据库开发人员提供全面的错误处理指南。

1. 背景介绍

1.1 目的和范围

在现代后端开发中,数据库存储过程作为业务逻辑的重要载体,其稳定性和可靠性直接影响整个系统的质量。本文旨在全面系统地介绍SQL存储过程中的错误处理机制,帮助开发人员构建更加健壮的数据库应用。

本文将涵盖以下范围:

  • 主流数据库系统(MySQL, SQL Server, Oracle, PostgreSQL)的错误处理机制
  • 存储过程中常见的错误类型和来源
  • 错误处理的核心概念和技术
  • 实际开发中的最佳实践和模式

1.2 预期读者

本文适合以下读者群体:

  1. 后端开发工程师,特别是负责数据库层开发的工程师
  2. 数据库管理员(DBA)需要维护和优化存储过程
  3. 全栈开发人员需要了解数据库错误处理机制
  4. 计算机科学专业学生学习数据库开发技术

1.3 文档结构概述

本文采用从基础到高级的结构:

  • 首先介绍核心概念和原理
  • 然后深入各种错误处理技术
  • 接着通过实际案例展示应用
  • 最后讨论高级主题和未来趋势

1.4 术语表

1.4.1 核心术语定义
  1. 存储过程(Stored Procedure): 预编译的SQL语句集合,存储在数据库中
  2. 错误处理(Error Handling): 检测、捕获和处理运行时错误的机制
  3. 事务(Transaction): 作为单个逻辑工作单元执行的一系列操作
  4. 异常(Exception): 程序执行过程中出现的意外情况
1.4.2 相关概念解释
  1. TRY-CATCH: 结构化错误处理机制,TRY块包含可能出错的代码,CATCH块处理错误
  2. 错误号(Error Number): 数据库系统分配给特定错误的唯一标识符
  3. 错误严重级别(Severity Level): 表示错误严重程度的数值
  4. 嵌套事务(Nested Transaction): 在现有事务内部启动的新事务
1.4.3 缩略词列表
  1. SP: Stored Procedure (存储过程)
  2. DML: Data Manipulation Language (数据操作语言)
  3. DCL: Data Control Language (数据控制语言)
  4. DDL: Data Definition Language (数据定义语言)
  5. T-SQL: Transact-SQL (SQL Server的SQL方言)
  6. PL/SQL: Oracle的过程化SQL语言

2. 核心概念与联系

2.1 存储过程错误处理的基本原理

SQL存储过程中的错误处理主要基于以下核心原理:

开始执行存储过程
    |
    v
[业务逻辑代码] --> [错误发生?] --是--> [错误处理机制]
    |                                   |
   否                                   v
    |                            [记录错误/回滚事务]
    v                                   |
[继续执行] <--[可恢复错误?]-- [是/否决定]

2.2 错误处理与事务管理的关系

错误处理与事务管理密切相关,Mermaid流程图展示它们的关系:

开始事务
执行操作
操作成功?
提交事务
回滚事务
记录错误
通知调用方

2.3 主流数据库的错误处理机制对比

特性 SQL Server MySQL Oracle PostgreSQL
TRY-CATCH 支持 8.0+支持 支持 支持
自定义错误号 支持 支持 支持 支持
错误日志 内置 需要实现 内置 需要实现
嵌套错误处理 支持 有限支持 支持 支持

2.4 错误传播机制

理解错误如何在存储过程调用链中传播至关重要:

  1. 当存储过程A调用存储过程B时
  2. 如果B中发生错误且未处理,错误会传播到A
  3. 如果A也没有处理,错误最终到达客户端应用程序
  4. 适当的错误处理可以中断这种传播或在传播过程中添加上下文信息

3. 核心算法原理 & 具体操作步骤

3.1 SQL Server的TRY-CATCH实现

SQL Server提供了完善的TRY-CATCH机制,以下是基本结构:

BEGIN TRY
    -- 可能出错的代码
    INSERT INTO Customers (Name, Email) VALUES ('John', '[email protected]');
END TRY
BEGIN CATCH
    -- 错误处理代码
    SELECT
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;

    -- 可选: 重新抛出错误
    THROW;
END CATCH

3.2 MySQL的存储过程错误处理

MySQL 5.5+使用DECLARE HANDLER语法:

DELIMITER //
CREATE PROCEDURE sp_add_customer(IN p_name VARCHAR(100), IN p_email VARCHAR(100))
BEGIN
    -- 声明处理程序
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        GET DIAGNOSTICS CONDITION 1
        @p1 = MYSQL_ERRNO, @p2 = MESSAGE_TEXT;

        -- 记录错误
        INSERT INTO error_log (error_number, error_message)
        VALUES (@p1, @p2);

        -- 返回错误信息
        SELECT CONCAT('Error: ', @p1, ' - ', @p2) AS ErrorMessage;
    END;

    -- 业务逻辑
    INSERT INTO customers (name, email) VALUES (p_name, p_email);
END //
DELIMITER ;

3.3 错误处理的具体操作步骤

  1. 识别潜在错误点: 分析存储过程中的哪些操作可能失败
  2. 确定错误处理策略: 决定是记录、重试、回滚还是传播错误
  3. 实现错误处理代码: 使用适当的语法添加错误处理
  4. 测试错误场景: 故意触发错误验证处理逻辑
  5. 优化错误信息: 确保错误信息对调用方有意义

3.4 嵌套存储过程的错误处理

处理嵌套存储过程调用时的错误需要特别注意:

CREATE PROCEDURE sp_outer_proc
AS
BEGIN
    BEGIN TRY
        -- 调用内层存储过程
        EXEC sp_inner_proc;

        -- 其他业务逻辑
        INSERT INTO Orders (CustomerID, OrderDate) VALUES (1, GETDATE());
    END TRY
    BEGIN CATCH
        -- 添加上下文信息后重新抛出
        DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
        DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
        DECLARE @ErrorState INT = ERROR_STATE();

        RAISERROR('Outer Proc Error: %s', @ErrorSeverity, @ErrorState, @ErrorMessage);
    END CATCH
END;

4. 数学模型和公式 & 详细讲解 & 举例说明

4.1 错误处理的概率模型

我们可以用概率论来评估错误处理策略的有效性。设:

  • P e P_e Pe 为单个操作失败的概率
  • n n n 为存储过程中的操作数量
  • P s p P_{sp} Psp 为整个存储过程失败的概率

假设各操作独立,则:

P s p = 1 − ( 1 − P e ) n P_{sp} = 1 - (1 - P_e)^n Psp=1(1Pe)n

这个公式说明,即使单个操作失败概率很低,随着操作数量增加,整体失败概率会显著上升。

4.2 错误处理的时间成本

错误处理会增加执行时间,可以表示为:

T t o t a l = T e x e c + P e × T e h T_{total} = T_{exec} + P_e \times T_{eh} Ttotal=Texec+Pe×Teh

其中:

  • T t o t a l T_{total} Ttotal 是总执行时间
  • T e x e c T_{exec} Texec 是无错误时的执行时间
  • T e h T_{eh} Teh 是错误处理时间

4.3 事务回滚的代价分析

事务回滚的代价与已执行操作数量相关:

C r o l l b a c k = ∑ i = 1 k C i C_{rollback} = \sum_{i=1}^{k} C_i Crollback=i=1kCi

其中 C i C_i Ci是第i个操作的回滚代价。这解释了为什么应该尽早检测错误,而不是在事务末尾统一处理。

4.4 错误分类的数学模型

我们可以用分类理论对错误进行建模。设错误集合为 E E E,可以划分为:

E = E r e c ∪ E u n r e c E = E_{rec} \cup E_{unrec} E=ErecEunrec

其中 E r e c E_{rec} Erec是可恢复错误, E u n r e c E_{unrec} Eunrec是不可恢复错误。良好的错误处理策略应最大化:

P ( e ∈ E r e c ∣ e ∈ E ) P(e \in E_{rec} | e \in E) P(eEreceE)

即给定错误发生,它是可恢复的条件概率。

5. 项目实战:代码实际案例和详细解释说明

5.1 开发环境搭建

SQL Server环境
  1. 安装SQL Server Developer Edition
  2. 安装SQL Server Management Studio (SSMS)
  3. 创建测试数据库:
    CREATE DATABASE ErrorHandlingDemo;
    GO
    USE ErrorHandlingDemo;
    GO
    
    -- 创建测试表
    CREATE TABLE Customers (
        CustomerID INT IDENTITY(1,1) PRIMARY KEY,
        Name NVARCHAR(100) NOT NULL,
        Email NVARCHAR(100) UNIQUE
    );
    
    CREATE TABLE Orders (
        OrderID INT IDENTITY(1,1) PRIMARY KEY,
        CustomerID INT FOREIGN KEY REFERENCES Customers(CustomerID),
        OrderDate DATETIME NOT NULL,
        Amount DECIMAL(10,2)
    );
    
    -- 错误日志表
    CREATE TABLE ErrorLog (
        LogID INT IDENTITY(1,1) PRIMARY KEY,
        ErrorNumber INT,
        ErrorMessage NVARCHAR(MAX),
        ErrorSeverity INT,
        ErrorState INT,
        ErrorProcedure NVARCHAR(128),
        ErrorLine INT,
        LogTime DATETIME DEFAULT GETDATE()
    );
    
MySQL环境
  1. 安装MySQL 8.0+
  2. 安装MySQL Workbench
  3. 创建测试数据库:
    CREATE DATABASE ErrorHandlingDemo;
    USE ErrorHandlingDemo;
    
    -- 创建测试表
    CREATE TABLE Customers (
        CustomerID INT AUTO_INCREMENT PRIMARY KEY,
        Name VARCHAR(100) NOT NULL,
        Email VARCHAR(100) UNIQUE
    );
    
    CREATE TABLE Orders (
        OrderID INT AUTO_INCREMENT PRIMARY KEY,
        CustomerID INT,
        OrderDate DATETIME NOT NULL,
        Amount DECIMAL(10,2),
        FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
    );
    
    -- 错误日志表
    CREATE TABLE ErrorLog (
        LogID INT AUTO_INCREMENT PRIMARY KEY,
        ErrorNumber INT,
        ErrorMessage TEXT,
        ErrorTime DATETIME DEFAULT CURRENT_TIMESTAMP
    );
    

5.2 源代码详细实现和代码解读

案例1:基本错误处理模式 (SQL Server)
CREATE PROCEDURE sp_add_customer_order
    @CustomerName NVARCHAR(100),
    @Email NVARCHAR(100),
    @OrderAmount DECIMAL(10,2)
AS
BEGIN
    SET NOCOUNT ON;

    -- 声明变量
    DECLARE @CustomerID INT;
    DECLARE @TranName VARCHAR(20) = 'CustomerOrderTran';

    BEGIN TRY
        BEGIN TRANSACTION @TranName;

        -- 插入客户记录
        INSERT INTO Customers (Name, Email)
        VALUES (@CustomerName, @Email);

        -- 获取新客户ID
        SET @CustomerID = SCOPE_IDENTITY();

        -- 验证金额是否为正
        IF @OrderAmount <= 0
        BEGIN
            RAISERROR('Order amount must be positive', 16, 1);
        END

        -- 插入订单记录
        INSERT INTO Orders (CustomerID, OrderDate, Amount)
        VALUES (@CustomerID, GETDATE(), @OrderAmount);

        -- 提交事务
        COMMIT TRANSACTION @TranName;

        -- 返回成功
        SELECT 'Success' AS Result, @CustomerID AS CustomerID;
    END TRY
    BEGIN CATCH
        -- 回滚事务
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION @TranName;

        -- 记录错误
        INSERT INTO ErrorLog (
            ErrorNumber, ErrorMessage, ErrorSeverity,
            ErrorState, ErrorProcedure, ErrorLine
        )
        VALUES (
            ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(),
            ERROR_STATE(), ERROR_PROCEDURE(), ERROR_LINE()
        );

        -- 返回错误信息
        SELECT 'Error' AS Result, ERROR_MESSAGE() AS ErrorMessage;
    END CATCH
END;

代码解读

  1. 使用TRY-CATCH块包裹整个业务逻辑
  2. 使用命名事务便于调试
  3. 包含业务规则验证(金额必须为正)
  4. 错误发生时回滚事务
  5. 记录详细错误信息到日志表
  6. 向调用方返回友好的错误信息
案例2:高级错误处理模式 (MySQL)
DELIMITER //
CREATE PROCEDURE sp_process_order(
    IN p_customer_id INT,
    IN p_amount DECIMAL(10,2),
    OUT p_result VARCHAR(100)
)
BEGIN
    -- 声明变量和处理器
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        -- 获取错误信息
        GET DIAGNOSTICS CONDITION 1
        @err_no = MYSQL_ERRNO, @err_msg = MESSAGE_TEXT;

        -- 记录错误
        INSERT INTO ErrorLog (ErrorNumber, ErrorMessage)
        VALUES (@err_no, @err_msg);

        -- 设置输出参数
        SET p_result = CONCAT('Error: ', @err_no, ' - ', @err_msg);

        -- 回滚
        ROLLBACK;
    END;

    -- 开始事务
    START TRANSACTION;

    -- 验证客户存在
    IF NOT EXISTS (SELECT 1 FROM Customers WHERE CustomerID = p_customer_id) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Customer does not exist';
    END IF;

    -- 验证金额
    IF p_amount <= 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Amount must be positive';
    END IF;

    -- 插入订单
    INSERT INTO Orders (CustomerID, OrderDate, Amount)
    VALUES (p_customer_id, NOW(), p_amount);

    -- 更新客户最后订单日期 (假设有此字段)
    UPDATE Customers SET LastOrderDate = NOW()
    WHERE CustomerID = p_customer_id;

    -- 提交事务
    COMMIT;

    -- 设置成功结果
    SET p_result = 'Success';
END //
DELIMITER ;

代码解读

  1. 使用DECLARE HANDLER语法定义错误处理器
  2. 使用GET DIAGNOSTICS获取详细错误信息
  3. 使用SIGNAL SQLSTATE抛出自定义错误
  4. 包含前置条件验证
  5. 使用输出参数返回结果
  6. 完整的事务管理(开始、提交、回滚)

5.3 代码解读与分析

错误处理策略分析
  1. 防御性编程:两个案例都验证了输入参数的有效性
  2. 事务完整性:确保操作要么全部成功,要么全部回滚
  3. 错误信息丰富性:捕获并记录尽可能多的错误上下文
  4. 调用方友好性:返回有意义的错误信息,而非原始数据库错误
性能考量
  1. 错误处理开销:TRY-CATCH块会增加少量性能开销,但远小于未处理错误的影响
  2. 日志记录优化:在高频操作中,考虑异步记录错误日志
  3. 事务范围:尽量缩小事务范围,减少锁持有时间
可维护性建议
  1. 统一错误处理:创建共享的错误处理存储过程
  2. 错误代码标准化:定义企业范围内的错误代码规范
  3. 文档化错误:维护错误代码和含义的文档

6. 实际应用场景

6.1 电子商务系统中的订单处理

在电商系统中,订单处理涉及多个步骤:库存检查、支付处理、订单创建、物流通知等。良好的错误处理可以:

  1. 确保库存数据一致性
  2. 正确处理支付失败情况
  3. 提供有意义的错误信息给前端
  4. 支持重试机制

6.2 银行系统的转账操作

银行转账需要极高的可靠性和数据一致性:

  1. 处理账户余额不足的情况
  2. 管理分布式事务
  3. 记录详细的审计日志
  4. 实现补偿事务机制

6.3 医疗系统的患者数据管理

医疗数据有严格的合规要求:

  1. 处理数据验证错误
  2. 确保HIPAA合规的错误信息
  3. 实现数据访问的完整审计
  4. 敏感操作的多重验证

7. 工具和资源推荐

7.1 学习资源推荐

7.1.1 书籍推荐
  1. “SQL Server Concurrency: Locking, Blocking and Row Versioning” by Kalen Delaney
  2. “SQL Server Internals” series by Paul Randal
  3. “High Performance MySQL” by Baron Schwartz
  4. “Oracle PL/SQL Programming” by Steven Feuerstein
7.1.2 在线课程
  1. “Advanced SQL: Logical Query Processing” (Pluralsight)
  2. “SQL Server: Understanding and Using Error Handling” (LinkedIn Learning)
  3. “MySQL for Developers” (Udemy)
  4. “Database Transactions and Error Handling” (Coursera)
7.1.3 技术博客和网站
  1. SQL Server Central (www.sqlservercentral.com)
  2. MySQL Official Blog (blogs.oracle.com/mysql)
  3. Brent Ozar’s SQL Server Blog (www.brentozar.com)
  4. PostgreSQL Wiki (wiki.postgresql.org)

7.2 开发工具框架推荐

7.2.1 IDE和编辑器
  1. SQL Server Management Studio (SSMS)
  2. Azure Data Studio
  3. MySQL Workbench
  4. DBeaver (多数据库支持)
7.2.2 调试和性能分析工具
  1. SQL Server Profiler
  2. Extended Events (XEvents)
  3. MySQL Enterprise Monitor
  4. pgBadger (PostgreSQL)
7.2.3 相关框架和库
  1. Entity Framework Core (ORM with error handling)
  2. Dapper (Micro-ORM with simple error handling)
  3. SQLAlchemy (Python ORM)
  4. JDBC (Java Database Connectivity)

7.3 相关论文著作推荐

7.3.1 经典论文
  1. “A Critique of ANSI SQL Isolation Levels” (1995)
  2. “ARIES: A Transaction Recovery Method Supporting Fine-Granularity Locking” (1992)
  3. “The End of an Architectural Era (It’s Time for a Complete Rewrite)” (2007)
7.3.2 最新研究成果
  1. “Anomaly Detection in Database Systems via Transactional Error Patterns”
  2. “Machine Learning Approaches for SQL Error Prediction”
  3. “Blockchain-based Transaction Error Recovery”
7.3.3 应用案例分析
  1. “Error Handling Patterns in Large-Scale Financial Systems”
  2. “Reliable Data Processing at Facebook”
  3. “Airbnb’s Approach to Database Reliability Engineering”

8. 总结:未来发展趋势与挑战

8.1 当前技术局限

  1. 跨数据库兼容性:不同DBMS的错误处理机制差异大
  2. 分布式事务:跨服务错误处理仍然复杂
  3. 错误诊断:生产环境中的错误根因分析困难
  4. 性能影响:全面错误处理可能影响吞吐量

8.2 新兴技术方向

  1. AI驱动的错误预测:使用机器学习预测潜在错误
  2. 自动修复系统:基于规则的自动错误恢复
  3. 声明式错误处理:定义期望状态而非具体处理步骤
  4. 云原生错误处理:利用云服务的弹性处理能力

8.3 长期挑战

  1. 平衡安全与性能:全面错误处理与系统响应时间的权衡
  2. 错误处理标准化:跨平台、跨语言的统一错误处理模型
  3. 开发人员教育:提高对错误处理重要性的认识
  4. 技术债务管理:遗留系统中的错误处理改造

9. 附录:常见问题与解答

Q1: 应该在存储过程还是应用代码中处理错误?

A: 两者都需要,但分工不同:

  • 存储过程处理数据库相关的错误(约束违反、死锁等)
  • 应用代码处理业务逻辑错误和聚合多个存储过程的错误
  • 黄金法则:在错误发生的地方最近的位置处理技术性错误,在更高层次处理业务逻辑错误

Q2: 如何处理存储过程中的死锁?

A: 死锁需要特殊处理:

  1. 在SQL Server中,死锁错误号为1205
  2. 通常应该重试几次(3-5次)
  3. 实现示例:
CREATE PROCEDURE sp_with_retry
AS
BEGIN
    DECLARE @retry INT = 0;
    DECLARE @max_retry INT = 3;
    DECLARE @success BIT = 0;

    WHILE @retry < @max_retry AND @success = 0
    BEGIN
        BEGIN TRY
            -- 业务代码
            SET @success = 1;
        END TRY
        BEGIN CATCH
            IF ERROR_NUMBER() = 1205 -- 死锁
            BEGIN
                SET @retry = @retry + 1;
                WAITFOR DELAY '00:00:00.1'; -- 短暂等待
            END
            ELSE
                THROW; -- 非死锁错误重新抛出
        END CATCH
    END
END;

Q3: 如何创建全局错误处理机制?

A: 可以创建中央错误处理存储过程:

CREATE PROCEDURE sp_log_error
    @ProcedureName NVARCHAR(128) = NULL,
    @AdditionalInfo NVARCHAR(MAX) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO ErrorLog (
        ErrorNumber, ErrorMessage, ErrorSeverity,
        ErrorState, ErrorProcedure, ErrorLine,
        AdditionalInfo
    )
    SELECT
        ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(),
        ERROR_STATE(), ISNULL(@ProcedureName, ERROR_PROCEDURE()), ERROR_LINE(),
        @AdditionalInfo
    WHERE ERROR_NUMBER() IS NOT NULL;

    -- 可选: 发送通知邮件等
END;

然后在其他存储过程中使用:

BEGIN CATCH
    EXEC sp_log_error @AdditionalInfo = 'Failed to process order';
    THROW;
END CATCH

Q4: 如何处理大批量操作中的部分失败?

A: 对于批量操作,考虑:

  1. 使用表变量或临时表跟踪成功/失败的记录
  2. 实现"继续或停止"的参数控制
  3. 示例模式:
CREATE PROCEDURE sp_bulk_insert_customers
    @Customers CustomerTableType READONLY,
    @StopOnError BIT = 1
AS
BEGIN
    DECLARE @Results TABLE (
        CustomerName NVARCHAR(100),
        Email NVARCHAR(100),
        Success BIT,
        ErrorMessage NVARCHAR(MAX)
    );

    DECLARE @Name NVARCHAR(100), @Email NVARCHAR(100);

    DECLARE customer_cursor CURSOR FOR
    SELECT Name, Email FROM @Customers;

    OPEN customer_cursor;
    FETCH NEXT FROM customer_cursor INTO @Name, @Email;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        BEGIN TRY
            INSERT INTO Customers (Name, Email)
            VALUES (@Name, @Email);

            INSERT INTO @Results (CustomerName, Email, Success, ErrorMessage)
            VALUES (@Name, @Email, 1, NULL);
        END TRY
        BEGIN CATCH
            INSERT INTO @Results (CustomerName, Email, Success, ErrorMessage)
            VALUES (@Name, @Email, 0, ERROR_MESSAGE());

            IF @StopOnError = 1
                THROW;
        END CATCH

        FETCH NEXT FROM customer_cursor INTO @Name, @Email;
    END

    CLOSE customer_cursor;
    DEALLOCATE customer_cursor;

    SELECT * FROM @Results;
END;

10. 扩展阅读 & 参考资料

  1. Microsoft Docs: “TRY…CATCH (Transact-SQL)”
    https://docs.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql

  2. MySQL Reference Manual: “Condition Handling”
    https://dev.mysql.com/doc/refman/8.0/en/condition-handling.html

  3. Oracle Documentation: “PL/SQL Error Handling”
    https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/plsql-error-handling.html

  4. PostgreSQL Documentation: “ERROR and RAISE Statements”
    https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html

  5. “Database System Concepts” by Abraham Silberschatz (第7章: 事务)

  6. “Transactions and Error Handling: A Case Study” (ACM SIGMOD Record)

  7. “Patterns of Error Handling in Database Applications” (IEEE Transactions on Software Engineering)

你可能感兴趣的:(sql,数据库,ai)