详解MySQL事务(超详细版)

🌈个人主页 :一条泥憨鱼 (欢迎各位大佬莅临)

🎬精选专栏:数据结构与算法JavaSE,苍穹外卖日记

前言:

"事务(Transaction)"是数据库开发里非常重要的知识。

简单来说:

事务就是"一组操作,要么全部成功,要么全部失败"。

它主要用于:

  • 转账

  • 下订单

  • 库存扣减

  • 支付系统

  • 多表更新

这些场景都不能只执行一半,否则数据就会出错。


一、为什么需要事务?

先看一个经典案例:

银行转账

假设:

  • 张三账户:1000 元

  • 李四账户:1000 元

现在张三给李四转 200 元。

正常流程:

复制代码
1. 张三 -200
2. 李四 +200

如果没有事务会发生什么?

假设:

复制代码
张三扣钱成功
↓
程序突然崩溃
↓
李四没收到钱

结果:

复制代码
张三:800
李四:1000

钱凭空消失了,这就是严重的数据错误。


有事务之后

事务会保证:

复制代码
要么两步都成功
要么两步都失败

这样数据永远正确。


二、事务的四大特性(ACID)

事务最核心,也是老生常谈的知识。


1. Atomicity(原子性)

原子性:

一个事务中的所有操作,要么全部完成,要么全部不完成。

比如:

复制代码
A扣钱
B加钱

不能只完成一半。


2. Consistency(一致性)

事务执行前后:

数据必须保持正确状态。

例如:

复制代码
转账前总金额:2000
转账后总金额:仍然2000

3. Isolation(隔离性)

多个事务之间:

彼此互不干扰。

比如:

复制代码
用户A正在修改数据
用户B不能读到中间状态

4. Durability(持久性)

事务提交后:

数据永久保存。

即使数据库崩溃,数据也不会丢失。


三、MySQL 中事务的基本操作

MySQL 提供了事务控制语句。


1. 开启事务

复制代码
START TRANSACTION;

或者:

复制代码
BEGIN;

2. 提交事务

复制代码
COMMIT;

提交后:

复制代码
数据永久生效

3. 回滚事务

复制代码
ROLLBACK;

回滚后:

复制代码
撤销事务中的所有操作

四、事务代码示例


创建测试表

账户表

java 复制代码
CREATE TABLE account(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(20),
    money DOUBLE
);

插入数据

java 复制代码
INSERT INTO account VALUES(NULL,'张三',1000);
INSERT INTO account VALUES(NULL,'李四',1000);

五、没有事务的问题

java 复制代码
UPDATE account SET money = money - 200 WHERE name='张三';

-- 程序崩溃

UPDATE account SET money = money + 200 WHERE name='李四';

这样会导致数据错误。


六、使用事务解决问题

java 复制代码
START TRANSACTION;

UPDATE account SET money = money - 200 WHERE name='张三';

UPDATE account SET money = money + 200 WHERE name='李四';

COMMIT;

如果发生异常

java 复制代码
START TRANSACTION;

UPDATE account SET money = money - 200 WHERE name='张三';

-- 出现错误

ROLLBACK;

这样:

复制代码
张三不会扣钱

数据库恢复原状。


七、Java 中操作事务

JavaWeb 开发里最常见。

一般使用:

  • JDBC

  • MyBatis

  • Spring

这里先讲 JDBC 原理。


八、JDBC 默认事务机制

JDBC 默认:

复制代码
自动提交事务

即:

复制代码
每执行一条SQL
自动commit

所以:

复制代码
conn.setAutoCommit(false);

非常重要。


九、JDBC 事务完整代码


转账案例

java 复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class Demo {

    public static void main(String[] args) {

        Connection conn = null;

        try {

            // 获取连接
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/test",
                    "root",
                    "123456");

            // 关闭自动提交
            conn.setAutoCommit(false);

            // 张三减200
            String sql1 =
                    "update account set money = money - 200 where name=?";

            PreparedStatement ps1 =
                    conn.prepareStatement(sql1);

            ps1.setString(1, "张三");

            ps1.executeUpdate();

            // 模拟异常
            int a = 1 / 0;

            // 李四加200
            String sql2 =
                    "update account set money = money + 200 where name=?";

            PreparedStatement ps2 =
                    conn.prepareStatement(sql2);

            ps2.setString(1, "李四");

            ps2.executeUpdate();

            // 提交事务
            conn.commit();

            System.out.println("转账成功");

        } catch (Exception e) {

            try {

                // 回滚事务
                if(conn != null){
                    conn.rollback();
                }

            } catch (Exception ex) {
                ex.printStackTrace();
            }

            System.out.println("转账失败");

        } finally {

            try {

                if(conn != null){
                    conn.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

十、事务执行流程图

复制代码
开始事务
   ↓
执行SQL1
   ↓
执行SQL2
   ↓
是否异常?
 ↓        ↓
否        是
 ↓         ↓
commit   rollback

十一、事务隔离级别

多个用户同时操作数据库时:

会产生并发问题。

MySQL 提供了:

四种隔离级别


1. Read Uncommitted(读未提交)

最低级别。

问题:

复制代码
脏读

即:

读取到别人未提交的数据。


2. Read Committed(读已提交)

解决:

复制代码
脏读

Oracle 默认级别。


3. Repeatable Read(可重复读)

MySQL 默认级别。

解决:

复制代码
脏读
不可重复读

4. Serializable(串行化)

最高级别。

事务串行执行。

最安全:

复制代码
性能最差

十二、并发问题详解


1. 脏读

事务A:

复制代码
修改余额但未提交

事务B:

复制代码
读取到了这个未提交的数据

如果A回滚:

复制代码
B读到的数据就是假的

2. 不可重复读

同一个事务:

复制代码
第一次读取:1000
第二次读取:1200

数据不一致。


3. 幻读

事务A读取:

复制代码
共有5条数据

事务B插入一条数据,事务A再次读取:

复制代码
变成6条

像"幻觉"一样。


十三、查看事务隔离级别

复制代码
SELECT @@transaction_isolation;

十四、设置事务隔离级别


设置当前会话

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

设置全局

复制代码
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

十五、事务失效的常见原因(面试常问)


1. 忘记提交

复制代码
COMMIT;

没写。


2. 自动提交未关闭

复制代码
conn.setAutoCommit(false);

没写。


3. 异常未捕获

导致:

复制代码
rollback未执行

4. 数据库引擎不支持事务

例如:

复制代码
MyISAM

不支持事务。


十六、InnoDB 与 MyISAM


InnoDB(推荐)

支持:

  • 事务

  • 行锁

  • 外键

MySQL 默认引擎。


MyISAM

不支持事务。

适合:

复制代码
读多写少

现在较少使用。


十七、Spring 事务(简单了解即可)

实际开发中,通常不会手写 JDBC 事务。

而是使用:

Spring 声明式事务

复制代码
@Transactional
public void transfer(){

}

Spring 自动:

  • 开启事务

  • 提交事务

  • 回滚事务

开发效率非常高。


十八、事务总结


核心一句话

事务就是保证多条SQL语句"要么全成功,要么全失败"。


事务控制语句

操作 SQL
开启事务 START TRANSACTION
提交事务 COMMIT
回滚事务 ROLLBACK

JDBC事务核心代码

java 复制代码
conn.setAutoCommit(false);

conn.commit();

conn.rollback();

MySQL 默认隔离级别

复制代码
Repeatable Read(可重复读)

开发中的最佳实践

推荐:

  • 使用 InnoDB

  • 使用 Spring 事务

  • 捕获异常后 rollback

  • 尽量缩小事务范围


十九、面试高频问题


1. 什么是事务?

事务是一组操作,要么全部成功,要么全部失败。


2. 事务四大特性?

复制代码
ACID
  • 原子性

  • 一致性

  • 隔离性

  • 持久性


3. MySQL 默认隔离级别?

复制代码
Repeatable Read

4. 如何开启事务?

复制代码
START TRANSACTION;

5. JDBC 如何控制事务?

复制代码
setAutoCommit(false)
commit()
rollback()

二十、学习建议

建议学习顺序:

复制代码
SQL事务
↓
JDBC事务
↓
事务隔离级别
↓
Spring事务
↓
分布式事务

这样会非常清晰。

相关推荐
一条泥憨鱼1 小时前
深入理解 MySQL 索引:原理、分类与优化实战
数据库·mysql
楠枬1 小时前
Redis 缓存
数据库·redis·缓存
j7~1 小时前
【MYSQL】 数据库的常见数据类型--详解
数据库·mysql·decimal·varchar·数据库的基本类型
二哈赛车手9 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
栗子~~10 小时前
JAVA - 二层缓存设计(本地缓冲+redis缓冲+广播所有本地缓冲失效) demo
java·redis·缓存
YDS82910 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— RAG知识库的搭建和接口实现
java·ai·springboot·agent·rag·deepseek
rising start10 小时前
二、全面理解MySQL架构
mysql·架构
星星也在雾里10 小时前
PgBouncer 解决 PostgreSQL 连接数超限 + 可视化监控
数据库·postgresql
bqq1986102611 小时前
MySQL性能优化
mysql·mysql优化