mysql为什么需要事务_mysql业务场景应用说明

来源:这里教程网 时间:2026-02-28 20:51:47 作者:

事务解决什么问题:不满足原子性的操作会怎样

MySQL 用事务,核心就为保证「要么全成功,要么全失败」。没有事务时,比如转账操作:

UPDATE accounts SET balance = balance - 100 WHERE id = 1
执行了,但紧接着
UPDATE accounts SET balance = balance + 100 WHERE id = 2
因网络中断或服务器宕机没执行——钱就凭空消失了。

这类跨行、跨表、需逻辑一致的修改,一旦中间出错又没回滚机制,数据库状态就会不一致。事务通过

BEGIN
/
COMMIT
/
ROLLBACK
把多个语句打包成一个不可分割的单元。

哪些业务场景必须开事务

不是所有

UPDATE
INSERT
都需要事务,但以下场景几乎必须加:

银行类资金操作:扣款+入账、充值+冻结、支付+库存扣减 订单创建全流程:生成订单记录 + 扣减商品库存 + 写入物流单号 + 更新用户积分 多表状态同步:用户注销时,要删
users
、清
user_sessions
、归档
user_logs
,缺一不可
幂等性兜底:接口重复提交时,靠事务+唯一约束(如
UNIQUE KEY (order_id, event_type)
)确保只生效一次

注意:单纯查数据(

SELECT
)、单行单表的简单更新(如
UPDATE config SET value = 'on' WHERE key = 'feature_x'
),一般不用事务。

autocommit 关掉还是开着:开发中容易踩的坑

MySQL 默认是

autocommit = 1
,即每条 SQL 自动提交。这看似省事,但会导致事务失效:

比如你写了

BEGIN
,然后执行两条
UPDATE
,最后
COMMIT
—— 如果中间某条语句报错(如违反外键约束),MySQL 不会自动回滚前面已执行的语句,除非你显式捕获错误并调用
ROLLBACK

更危险的是:应用层连接池复用连接时,如果上一个请求开了事务但没

COMMIT
ROLLBACK
,下一个请求可能在同一个事务上下文中执行,导致意外的数据锁定或脏读。

建议做法:

明确需要事务的逻辑,用
BEGIN
显式开启
应用代码里统一用 try-catch 包裹,出错必
ROLLBACK
,成功必
COMMIT
避免依赖
autocommit = 0
全局设置,它会让每个连接长期处于未提交状态,极易引发锁等待和连接堆积

隔离级别怎么选:READ COMMITTED 够用,别盲目上 SERIALIZABLE

MySQL 默认隔离级别是

REPEATABLE READ
,但它在高并发更新同一行时容易触发间隙锁(gap lock),导致不必要的锁冲突。实际业务中,多数场景用
READ COMMITTED
更轻量、更可控。

比如电商下单减库存:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT stock FROM products WHERE id = 123 FOR UPDATE;
-- 检查 stock > 0 后再 UPDATE
UPDATE products SET stock = stock - 1 WHERE id = 123;
COMMIT;

这个流程在

READ COMMITTED
下只锁住命中行,不会锁间隙;而
REPEATABLE READ
可能连
id = 124
的插入都拦住,影响并发吞吐。

SERIALIZABLE
几乎不用——它会让所有
SELECT
都加读锁,相当于把并发变成串行,响应延迟直接翻倍。

真正要注意的不是“选哪个最高级”,而是理解每个级别对锁行为和一致性的影响。线上出过问题的,往往是默认

REPEATABLE READ
下没意识到 gap lock 的存在,又没做充分压测。

相关推荐