写点什么

MySQL 事务:工作原理与实用指南

  • 2025-06-16
    福建
  • 本文字数:3159 字

    阅读完需:约 10 分钟

MySQL 事务:工作原理与实用指南


在数据库操作中,事务是保证数据一致性的重要机制。本文将深入探讨 MySQL 事务的特性、隔离级别以及实际应用场景,帮助你更好地理解和使用事务。


一、什么是事务?


事务是数据库操作的基本单位,它是一组原子性的 SQL 语句,或者说是一个独立的工作单元。事务内的所有操作要么全部成功,要么全部失败。


事务具有四个基本特性,通常称为 ACID 特性:

  1. 原子性(Atomicity)

  2. 一致性(Consistency)

  3. 隔离性(Isolation)

  4. 持久性(Durability)


-- 事务的基本示例START TRANSACTION;    UPDATE accounts SET balance = balance - 100 WHERE id = 1;    UPDATE accounts SET balance = balance + 100 WHERE id = 2;COMMIT;
复制代码


二、事务的 ACID 特性


1. 原子性(Atomicity)


原子性确保事务中的所有操作要么全部完成,要么全部不完成。如果事务执行过程中发生错误,所有已执行的操作都会回滚。


-- 原子性示例START TRANSACTION;    INSERT INTO orders (user_id, amount) VALUES (1, 100);    UPDATE inventory SET stock = stock - 1 WHERE product_id = 1;    -- 如果任何一步失败,整个事务都会回滚COMMIT;
复制代码


2. 一致性(Consistency)


一致性确保数据库从一个一致的状态转换到另一个一致的状态。事务执行前后,数据库的完整性约束不会被破坏。


-- 一致性示例START TRANSACTION;    -- 确保账户余额不会出现负数    UPDATE accounts SET balance = balance - 100     WHERE id = 1 AND balance >= 100;    UPDATE accounts SET balance = balance + 100     WHERE id = 2;COMMIT;
复制代码


3. 隔离性(Isolation)


隔离性确保并发执行的事务之间不会相互影响。每个事务都感觉不到其他事务的存在。


-- 隔离性示例-- 事务1START TRANSACTION;    SELECT balance FROM accounts WHERE id = 1;    -- 其他事务的修改不会影响这个查询结果COMMIT;
-- 事务2START TRANSACTION; UPDATE accounts SET balance = balance + 100 WHERE id = 1;COMMIT;
复制代码


4. 持久性(Durability)


持久性确保一旦事务提交,其所做的修改就会永久保存到数据库中。


-- 持久性示例START TRANSACTION;    INSERT INTO logs (message) VALUES ('重要操作');COMMIT;-- 提交后,数据已经持久化到磁盘
复制代码


三、事务的隔离级别


MySQL 提供了四种事务隔离级别:

  1. READ UNCOMMITTED(读未提交)

  2. READ COMMITTED(读已提交)

  3. REPEATABLE READ(可重复读)

  4. SERIALIZABLE(串行化)


-- 设置事务隔离级别SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
复制代码


1. READ UNCOMMITTED


最低的隔离级别,允许读取未提交的数据,可能导致脏读。


-- 事务1START TRANSACTION;    UPDATE accounts SET balance = balance + 100 WHERE id = 1;    -- 未提交
-- 事务2START TRANSACTION; SELECT balance FROM accounts WHERE id = 1; -- 可能读取到事务1未提交的数据COMMIT;
复制代码


2. READ COMMITTED


允许读取已提交的数据,避免脏读,但可能出现不可重复读。


-- 事务1START TRANSACTION;    SELECT balance FROM accounts WHERE id = 1;    -- 其他事务提交后,再次读取可能得到不同的结果COMMIT;
复制代码


3. REPEATABLE READ


确保在同一事务中多次读取同一数据得到相同的结果,避免不可重复读。


-- 事务1START TRANSACTION;    SELECT balance FROM accounts WHERE id = 1;    -- 即使其他事务提交了修改,再次读取仍得到相同结果COMMIT;
复制代码


4. SERIALIZABLE


最高的隔离级别,完全串行化执行事务,避免所有并发问题。


-- 事务1START TRANSACTION;    SELECT * FROM accounts WHERE id = 1 FOR UPDATE;    -- 其他事务无法修改该记录COMMIT;
复制代码


四、事务的常见问题


1. 脏读(Dirty Read)


一个事务读取了另一个事务未提交的数据。


-- 事务1START TRANSACTION;    UPDATE accounts SET balance = balance + 100 WHERE id = 1;    -- 未提交
-- 事务2START TRANSACTION; SELECT balance FROM accounts WHERE id = 1; -- 读取到事务1未提交的数据COMMIT;
复制代码


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


同一事务中多次读取同一数据得到不同的结果。


-- 事务1START TRANSACTION;    SELECT balance FROM accounts WHERE id = 1;    -- 其他事务修改并提交    SELECT balance FROM accounts WHERE id = 1;    -- 得到不同的结果COMMIT;
复制代码


3. 幻读(Phantom Read)


同一事务中多次读取同一范围的数据,得到不同的结果集。


-- 事务1START TRANSACTION;    SELECT * FROM accounts WHERE balance > 1000;    -- 其他事务插入新记录并提交    SELECT * FROM accounts WHERE balance > 1000;    -- 得到不同的结果集COMMIT;
复制代码


五、事务的最佳实践


1. 合理设置隔离级别


根据业务需求选择合适的隔离级别,在保证数据一致性的同时,避免不必要的性能开销。


-- 设置全局隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置会话隔离级别SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
复制代码


2. 控制事务大小


避免在事务中执行过多的操作,保持事务的简洁性。


-- 推荐的事务大小START TRANSACTION;    -- 执行必要的相关操作    UPDATE accounts SET balance = balance - 100 WHERE id = 1;    UPDATE accounts SET balance = balance + 100 WHERE id = 2;COMMIT;
复制代码


3. 使用保存点


在长事务中使用保存点,可以在出错时回滚到特定位置。


START TRANSACTION;    INSERT INTO orders (user_id, amount) VALUES (1, 100);    SAVEPOINT order_created;      UPDATE inventory SET stock = stock - 1 WHERE product_id = 1;    -- 如果库存更新失败,可以回滚到保存点    ROLLBACK TO SAVEPOINT order_created;COMMIT;
复制代码


4. 正确处理死锁


使用适当的超时设置和重试机制处理死锁。


-- 设置死锁超时SET innodb_lock_wait_timeout = 50;
-- 使用重试机制START TRANSACTION; -- 如果发生死锁,等待一段时间后重试 UPDATE accounts SET balance = balance - 100 WHERE id = 1;COMMIT;
复制代码


六、实际应用场景


1. 银行转账


确保转账操作的原子性和一致性。


START TRANSACTION;    -- 检查余额    SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;      -- 执行转账    UPDATE accounts SET balance = balance - 100 WHERE id = 1;    UPDATE accounts SET balance = balance + 100 WHERE id = 2;      -- 记录交易    INSERT INTO transactions (from_id, to_id, amount)     VALUES (1, 2, 100);COMMIT;
复制代码


2. 订单处理


确保订单创建和库存更新的原子性。


START TRANSACTION;    -- 创建订单    INSERT INTO orders (user_id, amount) VALUES (1, 100);      -- 更新库存    UPDATE inventory SET stock = stock - 1     WHERE product_id = 1 AND stock > 0;      -- 如果库存不足,回滚事务    IF ROW_COUNT() = 0 THEN        ROLLBACK;    ELSE        COMMIT;    END IF;
复制代码


3. 批量数据处理


使用事务确保批量操作的原子性。


START TRANSACTION;    -- 批量插入数据    INSERT INTO logs (message) VALUES     ('log1'), ('log2'), ('log3');      -- 更新统计信息    UPDATE statistics SET count = count + 3;COMMIT;
复制代码


七、总结


事务是数据库操作中保证数据一致性的重要机制。通过合理使用事务的 ACID 特性和隔离级别,我们可以:

  1. 确保数据操作的原子性

  2. 维护数据的一致性

  3. 控制并发访问

  4. 保证数据的持久性

在实际应用中,需要根据业务需求选择合适的隔离级别,并遵循事务的最佳实践,以在保证数据一致性的同时,获得良好的性能。


八、扩展阅读


  1. MySQL 事务隔离级别详解

  2. 数据库并发控制机制

  3. 分布式事务处理


文章转载自:大毛啊

原文链接:https://www.cnblogs.com/damaoa/p/18930567

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
MySQL事务:工作原理与实用指南_MySQL_不在线第一只蜗牛_InfoQ写作社区