MySQL的事务是什么?原理、ACID、隔离级别与实战详解

事务是MySQL InnoDB引擎最核心的能力,也是后端开发面试高频考点。转账、下单、扣库存等业务都离不开事务。本文用通俗语言讲清楚事务是什么、解决什么问题、ACID四大特性、隔离级别、常见坑点。

一、什么是事务

事务(Transaction)是把多条SQL打包成一个不可分割的执行单元。

单元内所有SQL:

  • 全部执行成功:执行commit提交,修改永久生效;
  • 任意一步失败:执行rollback回滚,撤销所有修改,回到执行之前的状态。

简单一句话:同生共死,要么全成,要么全败。

生活案例:转账

用户A给用户B转账200元,需要两条update语句:

  1. A的余额减少200
  2. B的余额增加200

如果没有事务:第一条执行成功,服务器宕机/程序报错,第二条没有执行。

结果:A钱扣掉了,B没有收到钱,产生脏数据。

开启事务之后:只要第二步失败,第一步的扣款操作就会全部撤销,不会出现中间异常状态。

⚠️注意:只有InnoDB引擎支持事务;MyISAM引擎不支持事务,commit、rollback不会生效。

二、事务四大特性 ACID

ACID是事务必须满足的四个核心属性,面试必背。

  1. 原子性(Atomicity)
    事务是最小执行单元,内部操作不可拆分。全部成功,或者全部失败回滚,不会停留在中间状态。

转账不能只扣钱不加钱。

  1. 一致性(Consistency)
    事务执行前后,业务数据整体合法一致。

转账前后,A+B总金额不变,不会凭空多出或者消失资金。原子性、隔离性、持久性最终都是为了保证一致性。

  1. 隔离性(Isolation)
    多个事务并发执行,互相之间要做到互相隔离。一个事务看不到另外一个事务未提交的数据。

多个同事同时操作同一笔账户,不能读到别人还没提交的中间临时数据。隔离性由事务隔离级别控制。

  1. 持久性(Durability)
    事务一旦commit提交成功,修改永久保存到磁盘,即使数据库宕机、断电,数据也不会丢失。依靠InnoDB redo log重做日志实现。

三、MySQL事务核心命令

手动SQL层面操作事务

sql 复制代码
-- 方式1:开启事务
START TRANSACTION; 

-- 执行多条DML语句 update / insert / delete
update account set balance=balance-200 where username='A';
update account set balance=balance+200 where username='B';

-- 全部成功,提交事务
COMMIT;

-- 如果出错,回滚所有修改
ROLLBACK;
  • START TRANSACTION:开启事务;
  • COMMIT:提交,持久化修改;
  • ROLLBACK:回滚,撤销本次事务所有变更;
  • SAVEPOINT 保存点名称:设置保存点,可以局部回滚,不用全部回滚;
  • ROLLBACK TO SAVEPOINT xxx:回滚到指定保存点。

MySQL默认autocommit=ON,每执行一条update/insert/delete就自动commit,相当于每条SQL自己就是一个独立事务。想要手动控制事务,需要关闭自动提交。

sql 复制代码
-- 关闭自动提交
SET autocommit = 0;

四、事务的4种隔离级别

并发场景下,不同隔离级别用来解决3种读现象:脏读、不可重复读、幻读。

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED(读未提交) 允许 允许 允许
READ COMMITTED(读已提交 RC) 禁止 允许 允许
REPEATABLE READ(可重复读 RR,MySQL默认) 禁止 禁止 允许(InnoDB通过MVCC解决幻读)
SERIALIZABLE(串行化) 禁止 禁止 禁止

三种并发问题通俗解释

  1. 脏读 :一个事务读到另一个事务还没有提交的数据,如果对方回滚,读到的数据就是无效脏数据。
  2. 不可重复读 :同一个事务内,同一条SQL前后查询,中间被其他事务提交修改,导致两次查询结果不一样。重点是数据内容被修改
  3. 幻读 :同一个事务,两次范围查询,别的事务插入/删除数据,导致前后返回行数不一样。重点是行数变化

MySQL InnoDB 默认隔离级别是 REPEATABLE READ,依靠MVCC多版本并发控制,在RR级别解决幻读问题。

查看当前隔离级别:

sql 复制代码
SELECT @@transaction_isolation;

设置隔离级别:

sql 复制代码
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

五、代码层面简单示例(pymysql)

python 复制代码
import pymysql

conn = pymysql.connect(
    host="127.0.0.1",
    user="root",
    password="xxx",
    database="test_db",
    charset="utf8mb4"
)
# 关闭自动提交,开启手动事务
conn.autocommit = False
cur = conn.cursor()

try:
    cur.execute("update account set balance=balance-200 where username=%s", ("A",))
    cur.execute("update account set balance=balance+200 where username=%s", ("B",))
    conn.commit()
    print("事务提交成功")
except Exception as e:
    conn.rollback()
    print(f"事务回滚,异常:{e}")
finally:
    cur.close()
    conn.close()

六、什么时候必须使用事务?

✅适合使用事务场景

  • 转账、资金交易;
  • 创建订单同时扣减库存;
  • 多表关联写入、更新,多条操作必须同时成功;
  • 业务逻辑要求多条SQL整体生效。

❌不需要事务场景

  • 单条insert/update/delete;
  • 纯查询select语句(查询不会修改数据)。

七、开发常见坑

  1. 忘记关闭autocommit:自动提交打开时,commit/rollback无效,每条SQL直接落库。
  2. 长事务:事务开启之后迟迟不commit/rollback。会占用锁、回滚段,造成大量锁等待,数据库性能暴跌。事务粒度尽量小。
  3. 事务使用不同connection连接:同一个事务所有SQL必须使用同一个连接对象,换连接就是全新事务。
  4. MyISAM引擎用事务:MyISAM不支持事务,commit/rollback调用没有效果。
  5. 异常捕获不执行rollback:发生异常不回滚,事务挂起,持续持有行锁。
  6. DDL语句(create/alter/drop)会隐式提交当前事务,DDL执行后前面的修改直接提交,无法回滚。

⚠️重点提醒:执行ALTER TABLE等DDL会触发隐式commit,会把之前未提交的事务直接提交,这个坑线上经常踩。

八、总结

  1. 事务是InnoDB引擎提供的能力,把多条SQL打包,保证要么全成功要么全失败。
  2. ACID四大特性:原子性、一致性、隔离性、持久性。
  3. 4种隔离级别用来控制并发读写行为,MySQL默认RR可重复读。
  4. 业务写操作尽量缩小事务范围,拒绝长事务;异常必须rollback。
  5. DDL语句会隐式提交事务,写代码要格外注意。

事务不是为了加快查询速度,而是保证数据一致性,防止业务产生脏数据。很多线上资金故障,根源就是没有合理使用事务。

相关推荐
上下求索,莫负韶华2 小时前
笔记-数据库事务和java事务和切面
java·数据库·笔记
黄华SJ520it2 小时前
顶俏洗衣液模式制度开发介绍:S2B2C社交分销+多门店核销系统全解析
前端·数据库·小程序·零售·系统开发
大黄说说2 小时前
Android 本地存储深度对比:SharedPreferences、MMKV、Room 数据库怎么选?
android·数据库
资讯第一线2 小时前
SQL Server工具:WinToolsPlus 之 SQL Server 日志清理/Suspect/质疑/置疑/可疑/单用户等 修复
数据库·oracle
追风少年ii2 小时前
课前准备--蛋白质PDB文件与PDBQT文件的格式与区别
数据库·数据分析·分子动力学·分子对接
hopsky3 小时前
《HBase 权威指南》 Lars George
大数据·数据库·hbase
Architect_Lee3 小时前
mac快速安装mysql
数据库·mysql·macos
Elastic 中国社区官方博客3 小时前
Elasticsearch:列式索引模式 - Columnar index mode
大数据·数据库·elasticsearch·搜索引擎·全文检索
冰暮流星3 小时前
mysql之查询
数据库·sql·mysql