触发器里不能用SELECT ... FOR UPDATE,因其会报错或引发死锁;正确做法是用OLD/NEW字段做前置计算校验,如IF NEW.balance + NEW.amount
触发器里不能用 SELECT ... FOR UPDATE
想在
UPDATE账户余额前查当前值做校验?别在触发器里写SELECT ... FOR UPDATE—— 大多数数据库(如 MySQL 5.7/8.0 默认事务隔离级别下)会直接报错ER_LOCK_WAIT_TIMEOUT或Can't update table 'account' in stored function/trigger。触发器运行时表锁/行锁状态复杂,显式加锁极易死锁或违反 SQL 标准限制。正确做法是:只依赖
OLD.balance和NEW.amount做前置计算校验,不查表。
- 假设业务规则是「变动后余额不得为负」,校验逻辑应写成:
IF NEW.balance + NEW.amount- 若需校验「单笔变动不得超过账户余额 20%」,则用:
ABS(NEW.amount) > 0.2 * OLD.balance(注意OLD.balance是变更前值)- MySQL 触发器中
NEW表示即将写入的行,OLD表示原行;PostgreSQL 用NEW/OLD同理,但语法略有不同(需声明BEFORE UPDATE并用RETURN NULL中断)INSERT/UPDATE/DELETE 必须分触发器处理
一个触发器只能绑定一种操作类型。想对
transaction表的插入、更新、删除都做余额校验?不能合在一个触发器里——MySQL 不支持BEFORE INSERT OR UPDATE这种写法。必须拆成三个独立触发器:
BEFORE INSERT ON transaction:校验插入的amount是否导致目标账户balance超限(需先查该账户当前余额,此处允许SELECT,因为是 INSERT 场景,无行锁冲突)BEFORE UPDATE ON transaction:重点校验amount修改是否引发余额违规(此时不能查账户表,要用OLD.account_id关联查,但更推荐把校验逻辑移到应用层或用存储过程封装)BEFORE DELETE ON transaction:通常无需余额校验,但若业务要求「已清算交易不可删」,可在此加IF OLD.status != 'cleared' THEN ...触发器无法捕获并发更新的中间态
两个事务同时更新同一账户:T1 读到余额 100,T2 也读到 100;T1 扣 80 → 写入 20;T2 扣 50 → 写入 50。最终余额变成 50,但两次扣款共 130,实际只剩 20 —— 触发器没报错,因为每次校验时看到的都是“当时有效的旧值”。
这是典型的“丢失更新”问题,触发器本身不提供串行化保障:
- 唯一可靠解法是应用层加
SELECT ... FOR UPDATE(在事务开始后、触发器执行前锁定账户行)- 或者改用带 CAS(Compare-And-Swap)语义的
UPDATE account SET balance = balance - ? WHERE id = ? AND balance >= ?,检查ROW_COUNT()是否为 1- MySQL 的
READ COMMITTED隔离级别下,触发器内SELECT看不到未提交变更,但无法避免上述竞态;只有SERIALIZABLE可缓解,但性能代价大PostgreSQL 的 AFTER ROW 触发器不适合强校验
PostgreSQL 支持
AFTER触发器,但此时数据已写入,SIGNAL抛异常会导致事务回滚——听起来可行?实际不行。因为AFTER触发器无法修改NEW行内容,也不能阻止写入发生(只是回滚),而你真正需要的是在写入前就否决非法操作。务必用
BEFORE ROW触发器,并在其中完成全部校验和修正(比如自动截断超额扣款):
- 错误写法:
AFTER UPDATE ON account→ 检查完再报错 → 数据已脏写一次- 正确写法:
BEFORE UPDATE ON account→ 计算NEW.balance := OLD.balance + NEW.delta→ 校验NEW.balance >= 0→ 不通过则RAISE EXCEPTION- 注意 PostgreSQL 中触发器函数需返回
NEW(允许修改)或NULL(取消操作),不能只RAISE就完事触发器能拦住明显违规,但拦不住并发下的逻辑漏洞。真要强一致性,得靠应用层加锁或数据库原生命令(如带
WHERE条件的原子更新),而不是指望触发器替你兜底。
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门AI工具
相关专题
数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。
4723
2023.10.12
SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。
971
2023.10.27
在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。
1229
2024.02.23
SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。
6721
2024.03.06
sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。
3443
2024.03.06
运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。
6700
2024.04.07
sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。
1250
2024.04.29
本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。
20
2026.11.02
热门下载
相关下载
精品课程
共6课时 | 12.1万人学习
共79课时 | 161.7万人学习
共6课时 | 54.7万人学习
最新文章










