事务操作
使用事务保证数据一致性,包括 BEGIN、COMMIT、ROLLBACK 和隔离级别设置
语法
START TRANSACTION | BEGIN; -- SQL statements COMMIT | ROLLBACK; SET TRANSACTION ISOLATION LEVEL level;
参数
| 参数 | 说明 | 示例 | 级别 |
|---|---|---|---|
BEGIN |
开始事务 | BEGIN; |
常用 |
COMMIT |
提交事务 | COMMIT; |
常用 |
ROLLBACK |
回滚事务 | ROLLBACK; |
常用 |
SAVEPOINT |
设置保存点 | SAVEPOINT sp1; |
进阶 |
SET TRANSACTION ISOLATION LEVEL |
设置隔离级别 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
进阶 |
示例
转账事务
BEGIN; -- 扣减付款方余额 UPDATE accounts SET balance = balance - 500.00 WHERE user_id = 1001 AND balance >= 500.00; -- 检查是否扣减成功(affected rows = 1) -- 增加收款方余额 UPDATE accounts SET balance = balance + 500.00 WHERE user_id = 1002; -- 记录转账流水 INSERT INTO transfer_logs (from_user, to_user, amount, created_at) VALUES (1001, 1002, 500.00, NOW()); COMMIT;
转账必须用事务,保证扣款和加款要么都成功要么都失败
下单扣库存事务
BEGIN;
-- 扣减库存(用 WHERE stock >= quantity 防止超卖)
UPDATE products SET stock = stock - 1
WHERE id = 2001 AND stock >= 1;
-- 检查 affected_rows,如果为 0 说明库存不足
-- 创建订单
INSERT INTO orders (order_no, user_id, product_id, total_amount, status)
VALUES ('ORD20260523001', 1001, 2001, 5999.00, 0);
COMMIT;
-- 如果任何步骤失败则 ROLLBACK;电商下单核心逻辑,防止超卖
使用 SAVEPOINT
BEGIN;
INSERT INTO orders (order_no, user_id, total_amount)
VALUES ('ORD001', 1001, 100.00);
SAVEPOINT before_items;
INSERT INTO order_items (order_id, product_id, quantity)
VALUES (LAST_INSERT_ID(), 2001, 2);
-- 如果订单项有问题,只回滚到保存点
ROLLBACK TO before_items;
-- 订单主记录保留
COMMIT;SAVEPOINT 允许部分回滚,不需要全部重来
查看和设置隔离级别
-- 查看当前隔离级别 SELECT @@transaction_isolation; -- 设置会话隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 隔离级别从低到高: -- READ UNCOMMITTED(脏读) -- READ COMMITTED(不可重复读) -- REPEATABLE READ(MySQL 默认,幻读) -- SERIALIZABLE(最严格,性能最差)
大多数互联网应用用 READ COMMITTED 即可
常见错误
ERROR 1213 (40001): Deadlock found when trying to get lock
两个事务互相等待对方释放锁。重试事务即可,同时优化事务中的 SQL 顺序保持一致
Lock wait timeout exceeded; try restarting transaction
其他事务持锁时间过长。检查是否有慢查询或未提交的事务:SHOW PROCESSLIST;
技巧
- 事务要尽量短小,持锁时间越长并发性能越差
- MySQL 默认 autocommit=1,每条 SQL 都是独立事务,需要手动 BEGIN 开启多语句事务
- 死锁时 MySQL 会自动回滚代价较小的事务,应用层需要捕获并重试