一、触发器基础概念
-
触发器的定义:一种由插入(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,触发器运行正常,满足反洗钱业务需求。