ACID特性
原子性(Atomicity):
事务是一个不可分割的工作单元,事务中的操作要么全部执行,要么全部不执行。
如果事务中的某个操作失败,则事务中的所有操作都应该被回滚(撤销),以保持数据库的一致性。
一致性(Consistency):
事务执行前后,数据库必须保持一致性状态。
一致性通常指数据约束、触发器、级联等规则在事务执行前后都能得到满足。
隔离性(Isolation):
并发事务之间应该相互隔离,一个事务的执行不应该影响其他事务的执行。
隔离性通过事务的隔离级别来控制,不同的隔离级别提供了不同程度的数据保护。
持久性(Durability):
一旦事务提交,其对数据库的改变应该是永久性的,即使系统崩溃也不会丢失。
持久性通常通过日志机制(如redo log)来实现,确保事务的提交结果能够持久保存。
MySQL事务支持
MySQL是一个支持多引擎的系统,但并非所有引擎都支持事务。
InnoDB是MySQL的默认存储引擎,它支持ACID事务。
MyISAM是MySQL的另一个常用存储引擎,但它不支持事务。
并发事务问题
脏读(Dirty Read):
一个事务读取了另一个事务未提交的数据。
脏读违反了隔离性原则,可能导致数据不一致。
不可重复读(Non-repeatable Read):
在同一个事务中,两次读取同一数据得到的结果不同,通常是因为另一个事务在两次读取之间修改了该数据。
不可重复读也违反了隔离性原则,但它允许其他事务提交对数据的修改。
幻读(Phantom Read):
在同一个事务中,两次查询同一范围的数据集时,第二次查询得到了与第一次查询不同的结果集(如新增了符合查询条件的行)。
幻读通常发生在范围查询中,一个事务在两次查询之间插入了新行。
幻读也违反了隔离性原则,因为它允许其他事务在两次查询之间插入新数据。
事务隔离级别
MySQL提供了四种事务隔离级别,以控制并发事务之间的相互影响:
未提交读(Read Uncommitted):
允许脏读,可能导致数据不一致。
提交读(Read Committed):
只能读取已提交的数据,避免脏读,但可能发生不可重复读和幻读。
可重复读(Repeatable Read):
保证在同一个事务中多次读取同一数据的结果相同,避免脏读和不可重复读,但可能发生幻读(InnoDB通过间隙锁来避免幻读)。
可串行化(Serializable):
通过强制事务顺序执行来避免所有并发问题,但性能开销大,通常不使用。
在MySQL的InnoDB存储引擎中,默认的事务隔离级别是可重复读(Repeatable Read)。
1. 若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是 2。
2. 若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。
3. 若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
4. 若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。
数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。
MVCC(多版本并发控制)
MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种用于实现数据库并发访问控制的机制,允许多个用户同时读写同一数据项,提高了数据库在高并发环境下的性能和响应速度。以下是对MVCC实现原理的详细解释:
一、核心组件
MVCC的实现主要依赖于以下两个核心组件:
Undo日志版本链:当一行数据被多个事务修改时,会保留修改前的数据作为Undo回滚日志。这些日志通过trx_id(事务ID)和roll_pointer(回滚指针)串联起来,形成一个历史记录版本链。版本链中的每个版本都记录了创建该版本的事务ID。
Read-View(一致性视图):在事务开始时(对于可重复读隔离级别,是第一个快照读操作时;对于读已提交隔离级别,是每个快照读操作时),会生成一个一致性视图。这个视图包含了当前系统中所有活跃事务的ID数组、当前最大的事务ID(max_id)和最小的事务ID(min_id)。事务中的任何查询都需要遵循版本链匹配规则和版本链里的最新数据逐条匹配,以得到最终的快照数据。
二、实现过程
数据读取:
当一个事务需要读取数据时,它会根据当前的事务隔离级别和一致性视图来判断哪些数据是可见的。
对于每个数据行,事务会查看其版本链,并根据版本链中的trx_id和一致性视图中的信息来判断该版本是否对当前事务可见。
如果版本对当前事务可见,则事务会读取该版本的数据;否则,事务会继续沿着版本链查找下一个版本,直到找到可见的版本或版本链结束。
数据修改:
当一个事务需要修改数据时,它会创建一个新的数据版本,并将该版本链接到旧版本上,形成新的版本链。
同时,事务会更新Undo日志,以便在需要时能够回滚到修改前的状态。
数据删除:
在MVCC中,删除操作并不会立即从数据库中删除数据行,而是将其标记为已删除,并保留在版本链中。
这样,其他事务在读取数据时仍然可以看到被删除数据行的旧版本(如果它们需要的话)。
三、读写操作的互不干扰
在MVCC中,读操作和写操作可以互不干扰地进行:
读操作:通过一致性视图和版本链匹配规则来确定可见的数据版本。读操作不会阻塞写操作,因为它读取的是事务开始时的数据快照。
写操作:在修改数据时,会生成一个新的数据版本,并更新Undo日志版本链。写操作也不会阻塞读操作,因为读操作读取的是旧版本的数据。
四、优点与缺点
优点:
提高了数据库的并发性能,因为读写操作可以互不干扰地进行。
减少了锁竞争,降低了死锁的风险。
提供了读取一致性,即一个事务在开始后只能看到在其开始时间之前提交的修改。
缺点:
增加了系统的复杂性,可能会增加设计和调试的难度。
在某些情况下,可能需要额外的存储空间来保存多版本的数据。
综上所述,MVCC是现代关系型数据库管理系统中一个至关重要的功能,它通过允许并行访问数据的方式来优化数据库的性能。理解其工作原理和实现方式有助于更好地设计和维护数据库应用,特别是在需要处理大量并发事务的环境中。
评论区