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

1次阅读

事务解决数据一致性问题:不满足原子性的操作会导致数据库状态不一致,如转账中扣款成功但入账失败,造成资金丢失。

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

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

mysql 用事务,核心就为保证「要么全成功,要么全失败」。没有事务时,比如转账操作:UPDATE accounts SET balance = balance - 100 WHERE id = 1 执行了,但紧接着 UPDATE accounts SET balance = balance + 100 WHERE id = 2 因网络中断或服务器宕机没执行——钱就凭空消失了。

这类跨行、跨表、需逻辑一致的修改,一旦中间出错又没回滚机制,数据库状态就会不一致。事务通过 BEGIN / COMMIT / ROLLBACK 把多个语句打包成一个不可分割的单元。

哪些业务场景必须开事务

不是所有 UPDATEINSERT 都需要事务,但以下场景几乎必须加:

  • 银行类资金操作:扣款+入账、充值+冻结、支付+库存扣减
  • 订单创建全流程:生成订单记录 + 扣减商品库存 + 写入物流单号 + 更新用户积分
  • 多表状态同步:用户注销时,要删 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

更危险的是:应用层连接池复用连接时,如果上一个请求开了事务但没 COMMITROLLBACK,下一个请求可能在同一个事务上下文中执行,导致意外的数据锁定或脏读。

建议做法:

  • 明确需要事务的逻辑,用 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 的存在,又没做充分压测。

text=ZqhQzanResources