什么是数据库的事务?

在之前的讨论中,我们已经了解了脏读、不可重复读和幻读这些并发问题,它们都源于多个事务同时执行时可能产生的数据不一致。要深入理解这些问题以及如何解决,就需要先掌握数据库事务的核心概念。

下面我会从事务的定义、ACID 属性、事务控制语句、隔离级别、实现机制以及实际应用这几个方面,为你系统地介绍数据库事务。


1. 什么是事务?

事务(Transaction)是数据库管理系统(DBMS)中执行的一组操作,这些操作要么全部成功,要么全部失败,不会出现部分成功、部分失败的情况。它是一个不可分割的工作单元。

典型场景:银行转账

  • 从账户A扣除100元
  • 向账户B增加100元

这两个操作必须作为一个整体来执行。如果只执行了第一步而第二步失败,数据库就会处于不一致状态。事务保证要么两步都完成,要么都不发生。


2. ACID 属性

事务的四大特性通常用 ACID 来概括:

A:原子性(Atomicity)

事务中的所有操作被视为一个原子单元,不可分割。

  • 如果事务执行过程中发生错误,已经执行的操作会回滚(Rollback),使数据库回到事务开始前的状态。
  • 实现机制:回滚日志(Undo Log) 记录操作前的旧值,以便在回滚时恢复。

C:一致性(Consistency)

事务必须使数据库从一个一致性状态转换到另一个一致性状态。

  • 一致性由应用层定义:例如转账前后,账户总金额不变;账户余额不能为负等。
  • 数据库通过约束(主键、外键、唯一性、检查约束)以及原子性、隔离性来帮助保证一致性。

I:隔离性(Isolation)

多个事务并发执行时,一个事务的执行不应被其他事务干扰。

  • 隔离性通过锁机制多版本并发控制(MVCC) 来实现。
  • SQL 标准定义了四种隔离级别,级别越高,隔离性越强,但并发性能越低。

D:持久性(Durability)

一旦事务提交,其对数据库的修改就是永久性的,即使系统发生故障(如断电、崩溃),数据也不会丢失。

  • 实现机制:重做日志(Redo Log) 在事务提交前将修改写入磁盘,保证崩溃后可以恢复。

3. 事务控制语句

在 SQL 中,事务通常通过以下语句控制:

  • BEGINSTART TRANSACTION:显式开始一个事务。
  • COMMIT:提交事务,使所有修改永久生效。
  • ROLLBACK:回滚事务,撤销当前事务中已执行的操作。
  • SAVEPOINT:设置保存点,允许部分回滚。
  • RELEASE SAVEPOINT:删除保存点。
  • ROLLBACK TO SAVEPOINT:回滚到指定保存点。

示例(MySQL):

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 检查无误后提交
COMMIT;
-- 如果出错则执行 ROLLBACK;

4. 并发问题与隔离级别

前面文章已经介绍了三种常见的并发问题:

问题描述
脏读读到其他事务未提交的数据
不可重复读同一事务内两次读取同一行数据,结果不同
幻读同一事务内两次范围查询,结果集行数不同

SQL 标准定义了四种隔离级别,每种级别能避免的问题如下:

隔离级别脏读不可重复读幻读
读未提交可能可能可能
读已提交不可能可能可能
可重复读不可能不可能可能(理论上)
串行化不可能不可能不可能
  • 读未提交:性能最高,但几乎没有隔离性。
  • 读已提交:大多数数据库(如 Oracle、SQL Server)的默认级别,避免脏读。
  • 可重复读:MySQL InnoDB 的默认级别,通过 MVCC + 间隙锁基本解决了幻读。
  • 串行化:最高隔离级别,所有事务串行执行,性能最低。

5. 事务的实现机制

数据库如何实现 ACID?主要依赖以下技术:

5.1 日志(Logging)

  • Undo Log:记录事务修改前的数据,用于回滚。
  • Redo Log:记录事务修改后的数据,用于故障恢复。
  • Binlog(MySQL):用于主从复制和基于时间点的恢复。

5.2 锁机制(Locking)

数据库使用锁来控制并发访问:

  • 共享锁(S锁):允许事务读取数据,其他事务只能加共享锁,不能加排他锁。
  • 排他锁(X锁):允许事务修改数据,阻止其他事务加任何锁。
  • 意向锁:用于层次锁(表级、行级)的协调。
  • 间隙锁(Gap Lock):锁定索引记录之间的间隙,防止幻读(MySQL InnoDB)。

5.3 多版本并发控制(MVCC)

MVCC 是“可重复读”和“读已提交”级别常用的并发控制技术。

  • 每行数据保存多个版本,通过创建版本号和删除版本号(或事务ID)来管理可见性。
  • 读操作通常读取“快照”,不加锁(快照读),写操作加锁(当前读)。
  • 这样读写不互斥,极大提高了并发性能。

6. 事务在实践中的注意事项

6.1 事务的粒度与时长

事务应尽可能短小,避免长时间占用资源。

  • 不要在事务中执行耗时的非数据库操作(如网络调用、复杂计算)。
  • 长事务可能导致锁等待、死锁、Undo 膨胀等问题。

6.2 死锁处理

多个事务互相等待对方释放锁时,就会发生死锁。

  • 数据库通常能自动检测死锁,并回滚其中一个事务。
  • 开发时可以通过约定加锁顺序使用较低隔离级别快速提交等方式减少死锁。

6.3 隔离级别的选择

  • 对一致性要求不高、追求高并发时,可用“读已提交”。
  • 需要防止不可重复读和幻读时,选择“可重复读”或“串行化”。
  • 注意不同数据库的默认级别和实现差异(如 MySQL 可重复读与 Oracle 可重复读表现不同)。

6.4 自动提交模式

很多数据库客户端默认开启自动提交,每个 SQL 语句就是一个独立的事务。

  • 在需要多个语句组成一个事务时,务必显式开启事务(START TRANSACTION)并关闭自动提交。

7. 总结

数据库事务是保证数据一致性和可靠性的核心机制。

  • ACID 定义了事务必须具备的特性。
  • 隔离级别 在一致性与并发性能之间提供权衡。
  • 日志、锁、MVCC 是数据库实现事务的三大支柱。
  • 在实际开发中,合理设计事务边界、选择合适的隔离级别、监控死锁和长事务,是写出健壮应用的关键。

如果你对某个具体方面(比如 MVCC 的详细原理、死锁排查方法、特定数据库的实现差异)感兴趣,我可以继续深入讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值