Mysql事务

发布于:2025-07-01 ⋅ 阅读:(18) ⋅ 点赞:(0)

🔥 MySQL 事务详解(超详细讲解)


🧭 一、事务是什么?

事务(Transaction) 是数据库操作的最小执行单元。事务中包含多条 SQL,这些 SQL 要么全部执行成功(提交 COMMIT),要么在某条失败时全部撤销(回滚 ROLLBACK)。

✅ 你可以这样理解:

就像 Java 中的 try-catch-finally,只不过这里是在数据库层。


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

特性 含义 示例
A - 原子性 一组操作是不可分割的整体 转账必须两个账户同时操作成功或失败
C - 一致性 操作前后数据都必须满足业务规则 钱没丢、没多出来,余额总和一致
I - 隔离性 多个事务互不干扰 你读我还没提交的数据?No way!
D - 持久性 提交后的数据永久保存 哪怕断电、重启也不能丢

⚙️ 三、MySQL 如何使用事务?

MySQL 默认使用 自动提交模式(autocommit=1),即每条 SQL 自动 COMMIT,所以事务要 手动开启

-- 开启事务(等价于 BEGIN)
START TRANSACTION;

-- SQL 操作
UPDATE account SET balance = balance - 500 WHERE id = 1;
UPDATE account SET balance = balance + 500 WHERE id = 2;

-- 提交事务
COMMIT;

-- 如果出错,可以回滚
ROLLBACK;

📌 ROLLBACK 表示撤销本事务中所有未提交的更改。


💡 四、事务示例:银行转账

假设我们有一个 account 表:

CREATE TABLE account (
    id INT PRIMARY KEY,
    name VARCHAR(20),
    balance DECIMAL(10,2)
);

事务操作流程:

START TRANSACTION;

-- 小池转500给小明
UPDATE account SET balance = balance - 500 WHERE name = '小池';
UPDATE account SET balance = balance + 500 WHERE name = '小明';

COMMIT;

如果第2步失败(比如账户不存在):

ROLLBACK;

🧠 五、事务的隔离级别(并发控制关键)

MySQL 使用 InnoDB 存储引擎时,支持以下 隔离级别

等级 问题解决 可能问题
READ UNCOMMITTED 脏读、不可重复读、幻读
READ COMMITTED 脏读 ❌ 不可重复读、幻读
REPEATABLE READ(默认) 脏读 ❌ 不可重复读 ❌ 幻读(可用 gap lock 解决)
SERIALIZABLE 所有问题都 ❌ 并发最低、锁多

🧪 六、常见并发问题举例

1. 脏读(Dirty Read)

A 读取了 B 尚未提交的修改,一旦 B 回滚,A 读的是无效数据。

2. 不可重复读(Non-repeatable Read)

A 两次读取同一行数据,B 在中间修改并提交,A 结果不一致。

3. 幻读(Phantom Read)

A 查询到的数据行数不同,因为 B 在中间插入了新的符合条件的数据。


🛠 七、事务 + Java 实战(JDBC + Spring)

✅ JDBC 手动控制事务

Connection conn = dataSource.getConnection();
try {
    conn.setAutoCommit(false); // 关闭自动提交

    // 执行 SQL
    PreparedStatement ps1 = conn.prepareStatement("UPDATE account SET balance = balance - ? WHERE id = ?");
    ps1.setBigDecimal(1, new BigDecimal("500"));
    ps1.setInt(2, 1);
    ps1.executeUpdate();

    PreparedStatement ps2 = conn.prepareStatement("UPDATE account SET balance = balance + ? WHERE id = ?");
    ps2.setBigDecimal(1, new BigDecimal("500"));
    ps2.setInt(2, 2);
    ps2.executeUpdate();

    conn.commit(); // 所有成功,提交
} catch (Exception e) {
    conn.rollback(); // 失败则回滚
    e.printStackTrace();
}

✅ Spring 声明式事务(最推荐)

@Transactional 一键控制事务:

@Service
public class TransferService {
    @Autowired
    AccountMapper accountMapper;

    @Transactional
    public void transfer(int fromId, int toId, BigDecimal amount) {
        accountMapper.decreaseBalance(fromId, amount);
        accountMapper.increaseBalance(toId, amount);
        // 如果中间抛异常,Spring 会自动 rollback
    }
}

注意:

  • 默认事务回滚的是运行时异常(RuntimeException);

  • 如果要回滚 checked 异常,可以这样配置:

@Transactional(rollbackFor = Exception.class)

📌 八、事务与存储过程

MySQL 的存储过程也支持事务控制:

CREATE PROCEDURE transfer(IN from_id INT, IN to_id INT, IN amt DECIMAL(10,2))
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    ROLLBACK;
  END;

  START TRANSACTION;
    UPDATE account SET balance = balance - amt WHERE id = from_id;
    UPDATE account SET balance = balance + amt WHERE id = to_id;
  COMMIT;
END;

✅ 总结:事务开发注意事项

建议 说明
开启事务前关闭自动提交 conn.setAutoCommit(false)
所有操作成功后再 commit() 别中途提交
捕获异常时记得 rollback() 防止数据不一致
数据库隔离级别合理配置 默认够用,但高并发时需调优
@Transactional 最省心 Spring 自动帮你控制事务


网站公告

今日签到

点亮在社区的每一天
去签到