事务与锁基础 === 事务和锁是 MySQL 中保证数据正确性与并发安全的核心机制。查询数据更多关注“如何把数据取出来”,而事务与锁关注的是“多个人同时操作数据时,如何保证结果仍然正确”。 ## 什么是事务 事务(Transaction)是一组不可再分的 SQL 操作,这组操作要么全部执行成功,要么全部执行失败,不会只完成一部分。 典型场景是转账: 1. A 账户扣款 2. B 账户加款 这两个步骤必须作为一个整体执行。如果只扣款成功、加款失败,数据就会出现错误,因此需要事务保证一致性。 ## 事务的四个特性 事务通常用 ACID 来描述: - 原子性(Atomicity):事务中的操作要么全部成功,要么全部失败。 - 一致性(Consistency):事务执行前后,数据都必须处于合法状态。 - 隔离性(Isolation):多个事务并发执行时,彼此之间尽量不互相干扰。 - 持久性(Durability):事务一旦提交,结果就会被持久保存。 ## 事务的基本操作 MySQL 中常见的事务控制语句如下: ```sql START TRANSACTION; UPDATE account SET balance = balance - 100 WHERE id = 1; UPDATE account SET balance = balance + 100 WHERE id = 2; COMMIT; ``` 如果执行过程中发现异常,可以回滚: ```sql START TRANSACTION; UPDATE account SET balance = balance - 100 WHERE id = 1; UPDATE account SET balance = balance + 100 WHERE id = 2; ROLLBACK; ``` 其中: - `START TRANSACTION` 表示开启事务 - `COMMIT` 表示提交事务 - `ROLLBACK` 表示回滚事务 ## 什么是锁 锁(Lock)是数据库在并发场景下保护数据的一种机制。当多个会话同时读写同一批数据时,MySQL 通过加锁来避免脏数据、覆盖更新和不一致问题。 可以把锁理解为“先占用资源,再进行操作”的规则。谁先拿到锁,谁就先操作;其他事务需要等待或按隔离规则读取。 ## 常见锁类型 ### 共享锁和排他锁 - 共享锁(Shared Lock,S 锁):允许多个事务同时读取同一条数据,但不允许修改。 - 排他锁(Exclusive Lock,X 锁):拿到锁的事务可以读写该数据,其他事务通常不能再加共享锁或排他锁。 ### 行锁和表锁 - 行锁:只锁定某几行记录,并发能力更强,影响范围更小。 - 表锁:锁定整张表,实现简单,但并发性能较低。 InnoDB 一般以行锁为主,因此更适合高并发业务场景。 ## 为什么需要锁 如果没有锁,在并发环境下容易出现以下问题: - 脏读:读取到另一个事务尚未提交的数据。 - 不可重复读:同一个事务中两次读取同一条记录,结果不同。 - 幻读:同一个事务中两次按条件查询,第二次多出或少了记录。 - 丢失更新:多个事务同时修改同一条记录,后一次覆盖前一次结果。 ## 事务隔离级别 MySQL 常见事务隔离级别包括: - READ UNCOMMITTED:隔离级别最低,可能出现脏读。 - READ COMMITTED:只能读到已提交数据,能避免脏读。 - REPEATABLE READ:同一事务中多次读取结果保持一致,是 InnoDB 默认级别。 - SERIALIZABLE:隔离级别最高,并发能力最低,安全性最强。 隔离级别越高,数据越安全,但并发性能通常越低,因此实际使用时要在一致性与性能之间平衡。 ## 查看和设置事务隔离级别 可以用下面的语句查看当前会话的隔离级别: ```sql SELECT @@transaction_isolation; ``` 也可以设置当前会话的隔离级别: ```sql SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ``` ## 使用事务与锁时的建议 1. 事务尽量短小,避免长事务占用锁太久。 2. 尽量通过索引命中目标行,减少锁范围。 3. 先查询再更新的业务,要注意并发竞争问题。 4. 批量更新和大事务要谨慎,避免阻塞其他会话。 5. 在高并发系统中,要结合事务隔离级别一起分析锁问题。 ## 小结 事务解决的是“操作要不要作为一个整体成功”的问题,锁解决的是“并发操作时谁可以先访问数据”的问题。掌握这两个基础概念后,再学习 MySQL 的更新、删除、索引优化和性能调优会更容易建立完整认识。