存储过程内begin transaction无效,因mysql和sql server默认autocommit=1,每条语句自动提交,事务边界必须由调用方显式开启并控制全程,否则rollback无目标。

直接在存储过程里 START TRANSACTION + ROLLBACK 是无效的,必须由调用方显式开启事务,否则回滚不生效。
为什么存储过程内部写 BEGIN TRANSACTION 没用
MySQL 和 SQL Server 都默认 autocommit=1,这意味着每条 DML 语句(INSERT/UPDATE/DELETE)执行完就自动提交。即使你在过程里写了 BEGIN TRANSACTION 或 START TRANSACTION,只要没关 autocommit,事务边界就不存在。
- SQL Server 中,
SET IMPLICIT_TRANSACTIONS OFF是默认值,autocommit实际由客户端连接控制;多数 ORM 或 SSMS 默认启用 autocommit - MySQL 中,
autocommit=1是全局默认,存储过程内无法覆盖该会话级设置 - 过程里执行 DDL(如
CREATE TEMPORARY TABLE)、或调用含隐式提交的操作(如ALTER TABLE),也会让前面所有 DML 提前落库
构造测试数据验证事务的正确姿势
核心原则:测试数据插入和事务控制必须分离——数据构造用独立脚本或过程,事务验证由外部调用者驱动。
- 先用干净的测试表(如
test_orders)或临时表(CREATE TEMPORARY TABLE test_log)构造输入数据 - 调用目标存储过程前,显式执行
START TRANSACTION(MySQL)或BEGIN TRAN(SQL Server) - 执行过程后,立刻查表确认变更存在;再执行
ROLLBACK,再次查表确认数据消失 - 若过程内含
COMMIT或SAVEPOINT,需提前注释掉,否则会破坏测试逻辑
容易被忽略的三个验证点
只看“有没有报错”或“返回值是不是 0”,根本验不出事务是否真回滚了。
- 查表时加
SELECT * FROM orders WHERE id = 123 FOR UPDATE,避免读到快照导致误判 - MySQL 下查
INFORMATION_SCHEMA.INNODB_TRX,确认trx_state = 'RUNNING'且trx_started时间匹配你的操作时间 - SQL Server 下查
sys.dm_tran_active_transactions,结合sys.dm_exec_sessions过滤当前会话
跨引擎要注意 MyISAM 和 InnoDB 混用
哪怕只有一张表是 MyISAM 引擎,整个事务就失去原子性——ROLLBACK 对它完全无效。
- 测试前统一执行
SHOW CREATE TABLE orders,确认ENGINE=InnoDB - 不要依赖建表语句里没写 ENGINE 就默认是 InnoDB;MySQL 8.0+ 默认是,但低版本或迁移库可能不是
- 临时表(
CREATE TEMPORARY TABLE)默认用 MEMORY 引擎,不支持事务;必须显式指定ENGINE=InnoDB











