SQL触发器实战:银行系统数据完整性控制

一、触发器基础概念

  • 触发器的定义:一种由插入(INSERT)、更新(UPDATE)、删除(DELETE)事件自动触发的特殊存储过程

  • 触发器的分类:AFTER(后触发)触发器、INSTEAD OF(替代触发器)

  • 本实验重点使用的是 AFTER 触发器

二、inserted 与 deleted 虚拟表

  • inserted表:存放 INSERT 或 UPDATE 操作产生的新数据行

  • deleted表:存放 DELETE 或 UPDATE 操作中被删除的旧数据行

  • 这两个表只在触发器作用域内存在,是触发器中数据访问的核心对象

三、触发器的创建与管理

  • 使用 CREATE TRIGGER创建触发器

  • 指定触发事件:ON 表名 AFTER INSERT / DELETE / UPDATE

  • 在触发器中使用 T-SQL 逻辑控制事务与业务规则

四、事务控制与数据约束

  • 使用 ROLLBACK TRANSACTION撤销违规的数据操作

  • 使用 RAISERROR抛出业务错误提示

  • 在触发器内结合 UPDATE、DELETE实现联动数据维护

  • 触发器与 CHECK约束、PRIMARY KEY、FOREIGN KEY的关系与区别

五、数据完整性控制(核心目标)

  • 实体完整性 :主键约束(PRIMARY KEY)

  • 域完整性 :CHECK约束、数据类型、长度校验(LEN()、LEFT())

  • 参照完整性:通过触发器实现级联删除与备份(弥补外键未定义的场景)

  • 业务完整性:余额校验、大额交易监控等业务规则由触发器实现

六、实际应用能力点

  • 利用触发器实现:

    • 业务规则校验(取款余额、卡号格式)

    • 自动数据更新(账户余额联动)

    • 级联操作(删除账户同时清理交易记录)

    • 数据备份与审计(反洗钱监测、历史数据归档)

七、实验概述

1. 实验目的

(1)理解并掌握 SQL Server 中触发器(Trigger)的工作原理;

(2)学会创建和使用 AFTER 触发器;

(3)能够利用触发器实现业务规则约束、数据自动维护与安全控制;

(4)通过实验加深对数据完整性控制机制的理解。

2. 实验环境

  • 硬件环境:个人计算机(PC)

  • 操作系统:Windows 10 / Windows 11

  • 数据库管理系统:Microsoft SQL Server

  • 开发语言:Transact-SQL(T-SQL)

3. 实验准备(建库、建表、初始数据)

复制代码
CREATE DATABASE bankSystem;
GO
USE bankSystem;
GO

CREATE TABLE bank(
    cardID varchar(8) PRIMARY KEY,
    customerName varchar(12),
    currentMoney money
);

CREATE TABLE transInfo(
    cardID varchar(8) NOT NULL,
    transDate datetime NOT NULL,
    transType varchar(8)
        CONSTRAINT cttype CHECK(transType='存入' OR transType='支取'),
    transMoney money,
    PRIMARY KEY(cardID, transDate)
);

INSERT INTO bank VALUES ('10010001','张三',1000);
INSERT INTO bank VALUES ('10010002','李四',1);

八、实验内容与实现过程

实验 1:取款操作触发器(tri_insert_transInfo)

(1)实验要求

当向交易信息表 transInfo 插入取款("支取")记录时,判断取款金额是否会导致账户余额低于 1 元。若合法,则自动更新账户余额;若不合法,则撤销取款操作。

(2)触发器代码
复制代码
CREATE TRIGGER tri_insert_transInfo
ON transInfo
AFTER INSERT
AS
BEGIN
    DECLARE @cardID varchar(8),
            @transMoney money,
            @balance money;

    SELECT @cardID = cardID,
           @transMoney = transMoney
    FROM inserted;

    SELECT @balance = currentMoney
    FROM bank
    WHERE cardID = @cardID;

    IF (@balance - @transMoney < 1)
    BEGIN
        RAISERROR('余额不足,取款失败!',16,1);
        ROLLBACK TRANSACTION;
    END
    ELSE
    BEGIN
        UPDATE bank
        SET currentMoney = currentMoney - @transMoney
        WHERE cardID = @cardID;
    END
END;
GO
(3)测试代码
复制代码
-- 合法取款
INSERT INTO transInfo
VALUES('10010001','2026-05-21','支取',500);

-- 非法取款
INSERT INTO transInfo
VALUES('10010002','2026-05-21','支取',1);
(4)实验结果与分析

第一次取款操作成功,账户余额由 1000 更新为 500;第二次取款因余额不足被触发器阻止,系统提示错误并回滚事务,数据未发生变化。


实验 2:银行卡号合法性触发器(tri_insert_cusID)

(1)实验要求

在 bank 表中新增账户时,要求银行卡号必须为 8 位,且必须以"10"开头,否则撤销插入操作。

(2)触发器代码
复制代码
CREATE TRIGGER tri_insert_cusID
ON bank
AFTER INSERT
AS
BEGIN
    DECLARE @cardID varchar(8);

    SELECT @cardID = cardID FROM inserted;

    IF (LEN(@cardID) <> 8 OR LEFT(@cardID,2) <> '10')
    BEGIN
        RAISERROR('卡号必须为8位且以10开头!',16,1);
        ROLLBACK TRANSACTION;
    END
END;
GO
(3)测试代码
复制代码
-- 合法插入
INSERT INTO bank VALUES('10010003','王五',2000);

-- 非法插入
INSERT INTO bank VALUES('90010004','赵六',3000);
(4)实验结果与分析

合法卡号成功插入表中;非法卡号被触发器拦截,插入操作被回滚,保证了数据的规范性。


实验 3:账户注销触发器(trig_delete_cusInfo)

(1)实验要求

当删除 bank 表中的账户时,同时删除该账户的所有交易记录,并将账户信息与交易信息备份到 backupBank 和 backupTransInfo 表中。

(2)触发器代码
复制代码
CREATE TRIGGER trig_delete_cusInfo
ON bank
AFTER DELETE
AS
BEGIN
    -- 备份账户信息
    IF NOT EXISTS(SELECT * FROM sysobjects WHERE name='backupBank')
        SELECT * INTO backupBank FROM deleted;
    ELSE
        INSERT INTO backupBank SELECT * FROM deleted;

    -- 备份交易信息
    IF NOT EXISTS(SELECT * FROM sysobjects WHERE name='backupTransInfo')
        SELECT * INTO backupTransInfo
        FROM transInfo
        WHERE cardID IN (SELECT cardID FROM deleted);
    ELSE
        INSERT INTO backupTransInfo
        SELECT * FROM transInfo
        WHERE cardID IN (SELECT cardID FROM deleted);

    -- 删除交易记录
    DELETE FROM transInfo
    WHERE cardID IN (SELECT cardID FROM deleted);
END;
GO
(3)测试代码
复制代码
DELETE FROM bank WHERE cardID = '10010001';
(4)实验结果与分析

账户成功删除,相关交易记录被同步删除,同时备份表中保存了被删除的数据,实现了数据的安全回收。


实验 4:反洗钱监测触发器(trig_Cashin_check)

(1)实验要求

当发生金额大于等于 500 万的大额存入交易时,将卡号、姓名、交易金额和交易时间自动写入 susTable 表,供反洗钱分析使用。

(2)触发器代码
复制代码
CREATE TRIGGER trig_Cashin_check
ON transInfo
AFTER INSERT
AS
BEGIN
    IF NOT EXISTS(SELECT * FROM sysobjects WHERE name='susTable')
        SELECT bank.cardID,
               bank.customerName,
               inserted.transMoney,
               inserted.transDate
        INTO susTable
        FROM inserted
        JOIN bank ON inserted.cardID = bank.cardID
        WHERE inserted.transType = '存入'
          AND inserted.transMoney >= 5000000;
    ELSE
        INSERT INTO susTable
        SELECT bank.cardID,
               bank.customerName,
               inserted.transMoney,
               inserted.transDate
        FROM inserted
        JOIN bank ON inserted.cardID = bank.cardID
        WHERE inserted.transType = '存入'
          AND inserted.transMoney >= 5000000;
END;
GO
(3)测试代码
复制代码
INSERT INTO transInfo
VALUES('10010001','2026-05-21','存入',6000000);
(4)实验结果与分析

普通存款不会触发该机制;当存款金额达到 600 万时,系统自动将该交易记录写入 susTable,触发器运行正常,满足反洗钱业务需求。

相关推荐
天行健,君子而铎16 分钟前
知形-数据库风险监测系统:非侵入式、可溯源、差异化的数据库安全方案
网络·数据库·安全
这个DBA有点耶18 分钟前
分布式事务深度:TCC空回滚、悬挂与Saga补偿风暴的根因与解法
数据库·mysql·代码规范
执笔为剑18 分钟前
2.1.2-2、V8R3迁移到V8R6-迁移介绍
数据库
hiahiahia12328 分钟前
Message 和对话
服务器·前端·数据库
又尔D.1 小时前
MySQL下载安装
数据库·mysql
Navicat中国1 小时前
Navicat 数据脱敏打造安全可用的仿真数据环境
数据库·数据安全·navicat·数据脱敏·合规
Elastic 中国社区官方博客1 小时前
Elastic 线下 Meetup 将于 2026 年 12 月 19 号下午在西安举行
大数据·数据库·elasticsearch·搜索引擎·ai·数据分析·全文检索
云絮.1 小时前
Mybatis(一)
java·数据库·mybatis
xiangyun611 小时前
C++ list 模拟实现(二):const迭代器与反向迭代器,模板的黑魔法
开发语言·数据库·c++·算法·stl·list