数据库实验五实战指南:事务、存储过程与触发器SQL脚本解析

发布时间:2026/10/31 2:28:18

数据库实验五实战指南:事务、存储过程与触发器SQL脚本解析 简介这份资源是西北工业大学软件学院数据库实验五的完整提交材料面向正在学习数据库课程、需要完成E-Commerce项目ER建模的学生。内容围绕电商项目描述中的需求给出完整的ER模式设计并附有ER图与文字说明便于对照理解实体、联系与属性的建模思路。压缩包共20个文件约282KB以14个gif操作截图、2个txt与2个doc实验文档、1个cdm概念数据模型文件及1个htm说明页为主截图覆盖注册、购物车、结算、订单确认等业务流程文档则记录实验要求与结果。已有911人学习下载适合需要参考建模过程、核对ER图细节或补做实验报告的同学使用可从中获取从需求分析到概念模型落地的完整思路与图示素材。1. 数据库实验五拆包一份能直接跑通的 SQL 落地资源数据库这门课实验一到实验四大多在讲建表、增删改查、视图和约束到了实验五画风通常就变了——开始碰事务、存储过程、触发器、游标这些“真家伙”。很多同学前四个实验还能照着课本敲到实验五就卡在“代码能跑但结果不对”“事务回滚没生效”“触发器递归爆栈”这类问题上。这份西北工业大学软件学院数据库实验五的资源包价值不在于它有多高深而在于它把实验五涉及的 SQL 脚本、建库脚本、测试数据和实验报告模板按实验流程组织好了拿到手就能对着跑一遍把事务隔离级别、存储过程参数传递、触发器触发时机这些容易翻车的点逐个验证。适合正在做数据库课程实验、需要一份可复现参考脚本的在校生也适合已经工作但想回头把 SQL 服务端编程补扎实的开发者。下面按“资源里有什么 → 怎么跑起来 → 参数怎么调 → 坑在哪”的顺序拆。2. 实验五的技术底座事务、存储过程与触发器怎么串起来实验五之所以比前面几个实验难是因为它不再是单条 SQL 的增删改查而是要求你把多条语句组织成一个逻辑单元并且保证这个单元要么全成功、要么全失败。资源包里的脚本正是围绕这个核心展开的所以动手之前得先把三块底座理清楚事务控制、存储过程、触发器。这三者不是孤立的实验里常见的组合是“存储过程内部开事务事务里更新多张表更新动作又触发触发器做审计”。不理解这个调用链跑脚本时看到的结果就会和预期对不上。2.1 事务控制BEGIN / COMMIT / ROLLBACK 的边界在哪事务的本质是把一组 DML 语句打包数据库保证这组语句的原子性。资源里的脚本一般会用BEGIN TRANSACTION或START TRANSACTION开头中间夹若干INSERT、UPDATE、DELETE最后用COMMIT提交或ROLLBACK回滚。看起来简单但边界判断是第一个坎哪些语句必须在事务内、哪些可以放在事务外直接决定回滚时数据会不会“回不干净”。我一般会这样组织一个可验证的事务脚本-- 开启事务注意不同数据库方言写法不同 BEGIN TRANSACTION; -- 第一步扣减库存条件里带库存判断防止超卖 UPDATE product SET stock stock - 1 WHERE product_id 1001 AND stock 1; -- 第二步写入订单明细 INSERT INTO order_detail (order_id, product_id, quantity) VALUES (2001, 1001, 1); -- 第三步检查第一步是否真的更新到了行没更新到就回滚 -- 这里用 ROWCOUNTSQL Server或 ROW_COUNT()MySQL判断 IF ROWCOUNT 0 BEGIN ROLLBACK TRANSACTION; PRINT 库存不足事务已回滚; END ELSE BEGIN COMMIT TRANSACTION; PRINT 下单成功事务已提交; END这段脚本的逻辑说明事务从BEGIN TRANSACTION开始到COMMIT或ROLLBACK结束中间任何一步失败都应该走回滚分支。参数上要注意两点一是WHERE条件里的stock 1是防超卖的关键少了它库存扣成负数事务照样提交二是行数判断函数因数据库而异SQL Server 用ROWCOUNTMySQL 用ROW_COUNT()PostgreSQL 则要看GET DIAGNOSTICS资源包如果按某个方言写换库跑就得改这一行。很多同学跑出来“明明库存不够却下单成功”八成就是漏了这个判断。2.2 存储过程参数模式 IN / OUT / INOUT 的差别存储过程是实验五的重头戏资源里的脚本通常会把一段业务逻辑封装成过程比如“根据商品 ID 和数量生成订单”。这里最容易混淆的是参数模式。IN是只进不出OUT是只出不进INOUT是既进又出。实验里常见需求是“传入商品 ID返回是否下单成功”这时候就得用OUT参数把结果带出来而不是靠SELECT打印。一个典型的带OUT参数的存储过程写法-- 创建存储过程p_result 为输出参数返回 1 成功 0 失败 CREATE PROCEDURE place_order ( IN p_product_id INT, IN p_quantity INT, OUT p_result INT ) BEGIN -- 声明异常处理器出错时回滚并置结果为 0 DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SET p_result 0; END; START TRANSACTION; UPDATE product SET stock stock - p_quantity WHERE product_id p_product_id AND stock p_quantity; -- 判断是否更新成功 IF ROW_COUNT() 0 THEN ROLLBACK; SET p_result 0; ELSE INSERT INTO order_detail (order_id, product_id, quantity) VALUES (FLOOR(RAND() * 100000), p_product_id, p_quantity); COMMIT; SET p_result 1; END IF; END;逻辑上这个过程把“扣库存 写订单”包在一个事务里用异常处理器兜底任何 SQL 异常都会触发回滚并把p_result置 0。参数说明p_product_id和p_quantity是输入调用时必须传实参p_result是输出调用前要先声明一个变量接住它。调用方式因方言不同MySQL 是CALL place_order(1001, 2, r); SELECT r;SQL Server 则是EXEC place_order 1001, 2, r OUTPUT; SELECT r;。这里有个血泪经验OUT参数在过程内部必须先赋值再返回如果某条分支忘了SET p_result调用方拿到的就是 NULL排查起来很费劲。2.3 触发器BEFORE 和 AFTER 的触发时机决定能不能改数据触发器是实验五里最容易被低估的部分。资源包里的触发器脚本一般用于审计比如“订单表插入后自动往日志表写一条记录”。关键点是触发时机BEFORE触发器在 DML 执行前触发可以修改即将插入或更新的数据AFTER触发器在执行后触发只能读不能改。实验里如果要求“插入订单时自动补全创建时间”那就得用BEFORE INSERT如果要求“插入后记录日志”用AFTER INSERT。-- AFTER INSERT 触发器订单插入后写审计日志 CREATE TRIGGER trg_order_audit AFTER INSERT ON order_detail FOR EACH ROW BEGIN INSERT INTO audit_log (table_name, action_type, record_id, log_time) VALUES (order_detail, INSERT, NEW.order_id, NOW()); END;这段代码里NEW是关键字代表刚插入的那行数据NEW.order_id取的就是新订单的 ID。参数上要注意FOR EACH ROW表示行级触发每插一行触发一次如果写成语句级触发批量插入时就只触发一次日志会漏记。另一个坑是触发器里不要再对同一张表做写操作否则容易触发递归或死锁这个后面避坑章节会细说。3. 把脚本跑起来建库、导数据、逐实验验证的完整流程拿到资源包后不要急着一条条复制粘贴正确姿势是先按依赖顺序把环境搭好再按实验步骤逐个验证。资源包里的文件通常分三类建库建表脚本、实验主体脚本事务/存储过程/触发器、测试数据脚本。顺序错了就会出现“表不存在”“外键约束失败”这类低级报错白白浪费时间。3.1 环境准备与建库脚本执行先确认数据库版本。资源包如果没写明方言从脚本里的ROWCOUNT、GO、TOP这些关键字能判断出是 SQL Server 系如果是ROW_COUNT()、DELIMITER、AUTO_INCREMENT那就是 MySQL 系。确认之后建一个独立库别在默认库上跑避免污染。# MySQL 环境下建库并导入建表脚本 mysql -u root -p -e CREATE DATABASE db_lab5 DEFAULT CHARACTER SET utf8mb4; mysql -u root -p db_lab5 schema.sql # 导入测试数据 mysql -u root -p db_lab5 seed_data.sql # 验证表是否建好 mysql -u root -p db_lab5 -e SHOW TABLES;命令说明-e后面跟的是要执行的 SQL是重定向导入文件。utf8mb4字符集建议显式指定实验里如果有中文商品名或备注用默认字符集可能存进去变问号。导入完成后用SHOW TABLES确认表数量与脚本预期一致少表通常是脚本中途报错被截断回头单独跑报错的那段看提示。SQL Server 环境下对应的是sqlcmd -S localhost -U sa -P 密码 -i schema.sql逻辑一样只是命令行工具不同。3.2 事务实验的验证方法用两个会话观察隔离级别事务实验光看脚本跑通不算完得验证隔离级别是否真的生效。资源里如果涉及“脏读”“不可重复读”的演示标准做法是开两个会话一个会话开事务改数据但不提交另一个会话去读看读到的是旧值还是新值。-- 会话 A开启事务并更新暂不提交 BEGIN TRANSACTION; UPDATE account SET balance balance - 100 WHERE account_id 1; -- 此处先不 COMMIT保持事务打开 -- 会话 B在另一个连接里查询同一行 SELECT balance FROM account WHERE account_id 1; -- 如果读到的是扣减后的值说明当前隔离级别允许脏读 -- 如果读到的是扣减前的值说明隔离级别至少是 READ COMMITTED验证逻辑会话 B 读到的结果取决于数据库当前隔离级别。MySQL 默认REPEATABLE READ会话 B 读不到未提交的修改SQL Server 默认READ COMMITTED同样读不到脏数据但会话 B 的读操作会被阻塞直到会话 A 提交或回滚。想演示脏读得手动把隔离级别降到READ UNCOMMITTED用SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;。这里提醒一句实验报告里写“观察到了脏读”之前先确认隔离级别真的改了否则结论是错的。3.3 存储过程与触发器的调用验证存储过程建好后用CALL或EXEC调用重点看OUT参数有没有正确返回、异常分支有没有走到。触发器则要验证“该触发的时候触发、不该触发的时候不触发”。-- 调用存储过程并查看输出参数 CALL place_order(1001, 2, result); SELECT result AS order_result; -- 验证触发器插入一条订单然后查审计日志 INSERT INTO order_detail (order_id, product_id, quantity) VALUES (3001, 1001, 1); SELECT * FROM audit_log WHERE record_id 3001; -- 预期能查到一条 INSERT 类型的日志查不到说明触发器没生效验证要点存储过程调用后result应该是 1 或 0如果是 NULL说明某条分支漏了赋值触发器验证时audit_log里查不到记录先确认触发器是否真的创建成功SHOW TRIGGERS;再确认插入是否真的执行了。资源包里如果有多个触发器注意它们之间的执行顺序同一时机多个触发器的触发顺序在不同数据库里行为不一致实验报告里最好注明测试环境。4. 参数与边界让实验结果对得上的几个关键设置脚本能跑不等于结果对。实验五的很多“玄学”问题根源在参数设置和边界条件没对齐。这一章把资源包里最常需要调整的几个点拎出来包括隔离级别、锁等待、触发器递归开关和存储过程的异常处理调对了这些结果才可复现。4.1 隔离级别与锁等待超时的配置隔离级别决定了并发事务之间能看到什么、会被阻塞多久。资源包如果演示并发场景建议显式设置隔离级别而不是依赖默认值这样换环境结果才一致。隔离级别脏读不可重复读幻读常见用途READ UNCOMMITTED可能可能可能演示脏读READ COMMITTED否可能可能多数业务默认REPEATABLE READ否否可能MySQL 默认SERIALIZABLE否否否强一致场景设置方式MySQL 用SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;SQL Server 用SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;。锁等待超时也要留意MySQL 默认innodb_lock_wait_timeout是 50 秒演示死锁时等 50 秒太磨人可以临时调小到 5 秒SET SESSION innodb_lock_wait_timeout 5;。调小之后死锁会更快报错方便观察。4.2 触发器递归与嵌套的开关触发器里如果对触发它的同一张表做写操作可能引发递归触发轻则日志重复重则栈溢出。MySQL 默认recursion_depth有限制SQL Server 有RECURSIVE_TRIGGERS开关。资源包里如果有“更新订单状态时写日志日志表又关联订单表”这种设计跑之前先确认递归开关状态。-- MySQL 查看当前递归深度限制 SHOW VARIABLES LIKE max_sp_recursion_depth; -- SQL Server 关闭递归触发器数据库级 ALTER DATABASE db_lab5 SET RECURSIVE_TRIGGERS OFF;建议实验环境里默认关闭递归触发器需要演示递归时再单独打开。关闭后如果业务逻辑依赖递归触发会表现为“日志只写了一条”这时候别急着怀疑脚本写错先查开关。4.3 存储过程异常处理的兜底写法存储过程里如果只写业务逻辑不写异常处理一旦中间某条语句报错事务可能悬空不提交也不回滚连接断开后才被动回滚实验里表现为“数据时对时不对”。稳妥写法是加EXIT HANDLERMySQL或TRY...CATCHSQL Server兜底。-- SQL Server 的 TRY...CATCH 兜底写法 CREATE PROCEDURE place_order_sqlserver product_id INT, quantity INT, result INT OUTPUT AS BEGIN SET result 0; BEGIN TRY BEGIN TRANSACTION; UPDATE product SET stock stock - quantity WHERE product_id product_id AND stock quantity; IF ROWCOUNT 0 THROW 50001, 库存不足, 1; INSERT INTO order_detail (order_id, product_id, quantity) VALUES (FLOOR(RAND() * 100000), product_id, quantity); COMMIT TRANSACTION; SET result 1; END TRY BEGIN CATCH IF TRANCOUNT 0 ROLLBACK TRANSACTION; SET result 0; END CATCH; END;这段的关键是BEGIN CATCH里先判断TRANCOUNT 0再回滚避免“没有活动事务却回滚”的二次报错。THROW用来主动抛异常让CATCH接住比用RAISERROR更清晰。参数上result在过程开头先置 0保证任何路径都有返回值不会出现 NULL。5. 避坑排查实验五最容易翻车的五个地方实验五的报错往往不直观同一个现象可能对应好几种原因。下面这五条是按“现象 → 原因 → 解决”整理的踩坑记录基本覆盖了资源包跑不通时的高频问题。5.1 事务回滚了但数据还在现象脚本里明明写了ROLLBACK查表发现数据还是被改了。原因通常是回滚之前已经隐式提交比如 MySQL 里执行了CREATE TABLE、ALTER TABLE这类 DDL 语句会隐式提交当前事务或者用了不支持事务的存储引擎MyISAM。解决确认表引擎是 InnoDBSHOW TABLE STATUS;看 Engine 列把 DDL 挪到事务外回滚前不要夹带任何隐式提交语句。5.2 存储过程调用报“参数数量不匹配”现象CALL place_order(1001, 2);报参数个数错误。原因过程定义里有OUT参数调用时必须传一个变量占位不能省略。解决先SET r 0;再CALL place_order(1001, 2, r);SQL Server 则要加OUTPUT关键字。这个坑新手几乎必踩因为IN参数可以省略不传有默认值时OUT参数不行。5.3 触发器不触发现象插入数据后审计表没记录。原因有三种常见情况触发器建在了错误的表上、触发时机写成了AFTER但业务需要BEFORE、或者插入操作本身因为约束失败没执行成功。解决先SHOW TRIGGERS;确认触发器存在且绑定表正确再单独跑一条最简单的INSERT看是否成功最后检查触发时机。如果插入被外键约束挡了触发器自然不会触发。5.4 死锁报错但复现不了现象实验要求演示死锁但跑脚本时有时报有时不报。原因死锁依赖两个事务的加锁顺序交叉单会话顺序执行永远复现不了必须两个会话并发且加锁顺序相反。解决开两个连接会话 A 先锁表 1 再锁表 2会话 B 先锁表 2 再锁表 1中间加SELECT ... FOR UPDATE或UPDATE制造排他锁就能稳定复现。注意锁等待超时要调小否则等太久。5.5 中文乱码或日期格式对不上现象插入的中文变成问号或者日期报“格式不正确”。原因库或表的字符集不是utf8mb4或者日期字符串格式与数据库期望的YYYY-MM-DD不一致。解决建库时显式指定字符集连接串加charsetutf8mb4日期统一用标准格式别用2024/1/1这种斜杠写法MySQL 严格模式下会直接报错。6. 进阶验证用执行计划和锁信息把实验做透脚本跑通只是及格线想把实验五做出深度得学会看执行计划和锁信息。资源包里的查询如果没走索引事务持有锁的时间会变长并发实验的结果就不稳定。我一般会在跑事务实验前先看一眼执行计划确认UPDATE和SELECT都走了索引再开并发。-- MySQL 查看执行计划重点看 type 和 rows EXPLAIN SELECT * FROM product WHERE product_id 1001; -- 查看当前锁等待情况MySQL 8.0 SELECT * FROM performance_schema.data_lock_waits; -- SQL Server 查看锁信息 EXEC sp_lock;EXPLAIN输出里type是ALL说明全表扫描事务更新时会锁住更多行并发实验容易互相阻塞改成ref或eq_ref说明走了索引锁范围小结果更可控。data_lock_waits能看到谁在等谁的锁演示死锁时用它佐证比只看报错更有说服力。参数上performance_schema需要开启MySQL 8.0 默认开5.7 可能要手动开。另一个进阶技巧是把实验五的存储过程改造成带版本号的审计方案每次更新订单状态时不覆盖原记录而是往历史表插一条新版本配合触发器自动记录变更前后值。这样既练了触发器又练了事务还能在实验报告里体现“可追溯”的设计思路。具体做法是在AFTER UPDATE触发器里用OLD和NEW关键字取变更前后的值CREATE TRIGGER trg_order_history AFTER UPDATE ON order_detail FOR EACH ROW BEGIN INSERT INTO order_history (order_id, old_quantity, new_quantity, change_time) VALUES (NEW.order_id, OLD.quantity, NEW.quantity, NOW()); END;OLD.quantity是更新前的值NEW.quantity是更新后的值两者都只在行级触发器里可用。这个写法在实验报告里能加分因为它同时体现了触发器、审计和事务一致性三个知识点。从那以后我每次跑数据库实验都会先EXPLAIN看一眼执行计划再开事务确认索引走了、锁范围可控才敢下并发结论。希望这份拆解帮到你把实验五从“能跑”做到“跑得明白”。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/31 2:28:18

VC++ ADO 参数化查询实战:Command 对象详解与避坑指南

简介:这份资源面向具备一定VC基础、希望掌握数据库访问技术的开发者,聚焦ADO中Command对象的实际运用,通过可编译的示例工程演示如何执行SQL语句、调用存储过程以及进行带参数的查询。压缩包共11个文件,约8KB,以cpp与h…

2026/10/31 2:28:18

OpenCV答题卡自动批改系统设计与实现

1. 项目概述:当OpenCV遇上教育场景去年帮本地一所中学处理月考答题卡时,手工批改300份试卷花了4个老师整整6小时。这促使我开始研究用OpenCV实现自动批卷的方案。通过摄像头或扫描仪获取答题卡图像后,系统能自动识别填涂区域、分析选项标记&a…

2026/10/31 2:28:18

数据科学中的提示工程架构设计与实践

1. 项目概述:数据科学中的提示工程架构设计在数据科学项目中,提示工程正从辅助工具演变为核心架构组件。作为从业12年的数据科学家,我亲历了从传统特征工程到提示工程的范式转变。不同于简单的提示词编写,提示工程架构设计需要系统…

2026/10/31 3:18:21

毫米波雷达二次反射感知技术解析与应用

1. 项目概述:毫米波雷达的二次反射感知革命SeRadar代表了一种突破性的毫米波雷达人体感知技术,它不再局限于传统的一次反射信号分析,而是创新性地利用了环境中的二次反射信号。这种技术路径的转变,就像在黑暗房间中不仅观察直接照…

2026/10/31 3:18:21

Redis事务机制与ACID特性详解

1. Redis事务基础概念Redis事务提供了一种将多个命令打包执行的机制,与传统数据库事务不同,Redis事务的设计更注重简单性和高性能。在Redis中,事务通过MULTI、EXEC、DISCARD和WATCH四个核心命令实现。1.1 事务执行流程Redis事务执行分为三个阶…

2026/10/31 3:18:21

本地语音识别+蓝牙控制:离线智能家居原型实战

简介:这份资源面向电子信息、嵌入式与物联网方向的毕业设计学生及DIY爱好者,提供一套可基本实现功能的语音控制智能家居完整工程,解决从语音识别、蓝牙通信到设备控制的软硬件联调问题。压缩包共2358个文件、约33.89MB,涵盖Androi…

2026/10/31 3:18:21

Linux硬链接与符号链接:inode原理、ln实操与断链排查

前两天团队里一位开发者发来消息,说发布目录里的静态资源整站 404,重启服务也没用。我上去看了一眼,ls -l里那个current后面挂着一行红色的-> /srv/app/releases/v1.2.3,而releases下面这个目录早就被清理脚本删掉了。问题不是…

2026/10/31 3:18:20

TypeScript插件系统实战:plugin.json、SDK与CLI加载失败排查

1. 从"plugins"这个标题说起:插件系统到底在解决什么问题"plugins"这个词单独拎出来,信息量其实非常少。但结合热搜词里反复出现的cursor、plugin.json、TypeScript SDK、CLI、harness failed to load plugins这些关键词&#xff0c…

2026/10/31 3:13:20

基于协同过滤的美食推荐系统设计与优化

1. 项目概述:当美食遇上算法去年帮学弟调试这个毕设系统时,我们站在回民街的烤肉摊前突然意识到:在西安这座碳水之都,游客面对琳琅满目的泡馍、肉夹馍、凉皮时,选择困难症比代码报错还难解决。这个基于协同过滤的美食推…

2026/10/30 20:55:10

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/30 20:55:10

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/30 20:55:09

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/31 0:02:41

猫狗目标检测数据集:VOC/COCO/YOLO三格式一体化实战包

简介:本资源是一套面向计算机视觉初学者与YOLO目标检测实践者的猫狗图像数据集及配套开发工具包,专为快速上手目标检测模型训练而设计。资源包含1000张真实场景高清猫狗图片,标注质量高,同时提供VOC(XML)、…

2026/10/31 0:02:41

HDU2017多校标程复现:算法竞赛工程化真题沙盒

简介:本资源为2017年HDU多校联合训练第一场官方配套资料,面向ACM程序设计竞赛备赛学生、算法爱好者及高校编程集训队成员,旨在提供权威解题参考与完整测试验证环境。压缩包共40个文件,含15份C标程(覆盖全部赛题&#x…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑