数据库事务是作为单个逻辑工作单元执行的一系列操作,具有ACID特性,并发执行可能引发问题,死锁是并发锁竞争导致的特殊阻塞状态。以下是具体介绍:
数据库事务原理事务是数据库的逻辑工作单位,通过ACID特性保障数据完整性:
- 原子性:操作要么全部执行,要么全部不执行。例如转账时,扣款和到账必须同时成功或失败。
- 一致性:事务前后数据满足完整性约束。如账户余额不能为负,若原子性失效(如系统故障导致部分操作未完成),数据将处于不一致状态。
- 隔离性:并发事务互不干扰。通过隔离级别(如读未提交、读已提交、可重复读、串行化)控制隔离效果,防止脏读、不可重复读等问题。
- 持久性:事务提交后,数据改变永久生效。即使系统故障,已提交的数据也不会丢失。
事务运行模式包括自动提交(默认)、显式事务(通过BEGIN/COMMIT/ROLLBACK控制)和隐性事务(自动启动新事务)。以MySQL InnoDB为例,通过WAL协议实现ACID:
- 重做日志(redo):记录事务修改,确保数据持久化。事务提交时,日志先写入磁盘,再异步更新数据文件。
- 回滚日志(undo):记录反向操作,支持事务回滚。undo存储在特殊段中,与redo分离。
并发问题并发事务可能引发以下问题:
- 脏读:读取未提交数据。如事务A修改数据未提交,事务B读取后,A回滚导致B读取无效数据。
- 丢失更新:后提交事务覆盖前事务修改。如两个事务同时更新同一行,后提交者覆盖前者结果。
- 不可重复读:同一事务内多次读取同一数据结果不同。如事务A读取数据后,事务B修改该数据,A再次读取时结果变化。
- 幻读:同一事务内多次查询数据总量不同。如事务A查询数据后,事务B新增数据,A再次查询时总量增加。
为解决并发问题,事务控制演进为:
- 排队:串行化处理,效率低。
- 排它锁:互斥锁,阻塞其他事务访问已锁定数据。
- 读写锁:读操作共享锁,写操作排它锁。
- MVCC:多版本并发控制,通过版本链实现读写不阻塞。
死锁死锁是两个或多个事务互相等待对方释放锁,形成循环依赖。例如:
- 事务A锁定行1,请求行2的排它锁;事务B锁定行2,请求行1的排它锁。此时,A等待B释放行2,B等待A释放行1,导致永久阻塞。
数据库引擎通过死锁监视器检测循环依赖,选择牺牲品事务终止并返回错误。死锁与普通阻塞的区别在于:
- 死锁:涉及多个事务的循环等待,需外部干预解除。
- 普通阻塞:单事务等待另一事务释放锁,最终可完成。
为避免死锁,可优化事务设计(如按固定顺序访问资源)、减少事务持有锁时间或设置合理的隔离级别。