Skip to main content

Transaction Processing

本文摘自 周志明 凤凰架构:构建可靠的大型分布式系统

本地事务

原子性和持久性

本地事务定义:只适用于单个服务使用单个数据源

本地事务实现机制:同时满足原子性和持久性。在发生奔溃时,系统能通过Commit Logging 进行恢复,或者使用Shadow Paging 进行本地事务;

  • Commit Logging 通过重做日志(Redo Log)将已经提交但是未完全持久化的数据,根据日志进行重放;
  • Commit Logging 通过回滚日志(Undo Log)将已经写入数据改回回去

隔离性

  • 写锁(Write Lock,也叫作排他锁,eXclusive Lock,简写为 X-Lock):如果数据有加写锁,就只有持有写锁的事务才能对数据进行写入操作,数据加持着写锁时,其他事务不能写入数据,也不能施加读锁。
  • 读锁(Read Lock,也叫作共享锁,Shared Lock,简写为 S-Lock):多个事务可以对同一个数据添加多个读锁,数据被加上读锁后就不能再被加上写锁,所以其他事务不能对该数据进行写入,但仍然可以读取。对于持有读锁的事务,如果该数据只有它自己一个事务加了读锁,允许直接将其升级为写锁,然后写入数据。
  • 范围锁(Range Lock):对于某个范围直接加排他锁,在这个范围内的数据不能被写入。

加了范围锁后,不仅无法修改该范围内已有的数据,也不能在该范围内新增或删除任何数据

范围锁写法 SELECT * FROM books WHERE price < 100 FOR UPDATE;

可串行化(Serializable)对事务所有读、写的数据全都加上读锁、写锁和范围锁;

**问题 **并发差。

可重复读(Repeatable Read)对事务所涉及的数据加读锁和写锁,且一直持有至事务结束,但不再加范围锁;

**问题 **幻读,原因是可重复读没有范围锁来禁止在该范围内插入新的数据。

读已提交(Read Committed)对事务涉及的数据加的写锁会一直持续到事务结束,但加的读锁在查询操作完成后就马上会释放。读已提交级别是要求先加读锁后读数据的

问题 不可重复读 两次查询可能会得到不一样的结果,原因是读已提交的隔离级别缺乏贯穿整个事务周期的读锁,无法禁止读取过的数据发生变化(没有读锁就是可以加写锁,所以数据变了)

读未提交(Read Uncommitted)对事务涉及的数据只加写锁,会一直持续到事务结束,但完全不加读锁。读未提交级别是可以不加读锁读取数据

问题 脏读原因是读未提交在数据上完全不加读锁,这反而令它能读到其他事务加了写锁的数据

共同点 :

就是幻读、不可重复读、脏读等问题都是由于一个事务在读数据过程中,受另外一个写数据的事务影响而破坏了隔离性,针对这种“一个事务读+另一个事务写”的隔离问题,近年来有一种名为“多版本并发控制”(Multi-Version Concurrency Control,MVCC)的无锁优化方案被主流的商业数据库广泛采用

根据以下规则写入数据

  • 插入数据时:CREATE_VERSION 记录插入数据的事务 ID,DELETE_VERSION 为空。
  • 删除数据时:DELETE_VERSION 记录删除数据的事务 ID,CREATE_VERSION 为空。
  • 修改数据时:将修改数据视为“删除旧数据,插入新数据”的组合,即先将原有数据复制一份,原有数据的 DELETE_VERSION 记录修改数据的事务 ID,CREATE_VERSION 为空。复制出来的新数据的 CREATE_VERSION 记录修改数据的事务 ID,DELETE_VERSION 为空。

此时,如有另外一个事务要读取这些发生了变化的数据,将根据隔离级别来决定到底应该读取哪个版本的数据。

  • 隔离级别是可重复读:总是读取 CREATE_VERSION 小于或等于当前事务 ID 的记录,在这个前提下,如果数据仍有多个版本,则取最新(事务 ID 最大)的。
  • 隔离级别是读已提交:总是取最新的版本即可,即最近被 Commit 的那个版本的数据记录。
Agreement
The code part of this work is licensed under Apache License 2.0 . You may freely modify and redistribute the code, and use it for commercial purposes, provided that you comply with the license. However, you are required to:
  • Attribution: Retain the original author's signature and code source information in the original and derivative code.
  • Preserve License: Retain the Apache 2.0 license file in the original and derivative code.
The documentation part of this work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . You may freely share, including copying and distributing this work in any medium or format, and freely adapt, remix, transform, and build upon the material. However, you are required to:
  • Attribution: Give appropriate credit, provide a link to the license, and indicate if changes were made.
  • NonCommercial: You may not use the material for commercial purposes. For commercial use, please contact the author.
  • ShareAlike: If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.