Skip to main content

事务处理

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

本地事务

原子性和持久性

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

本地事务实现机制:同时满足原子性和持久性。在发生奔溃时,系统能通过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 的那个版本的数据记录。
协议
  • 本作品代码部分采用 Apache 2.0协议进行许可。遵循许可的前提下,你可以自由地对代码进行修改,再发布,可以将代码用作商业用途。但要求你:

    • 署名:在原有代码和衍生代码中,保留原作者署名及代码来源信息。
    • 保留许可证:在原有代码和衍生代码中,保留Apache 2.0协议文件。
  • 本作品文档部分采用知识共享署名 4.0 国际许可协议进行许可。 遵循许可的前提下,你可以自由地共享,包括在任何媒介上以任何形式复制、发行本作品,亦可以自由地演绎、修改、转换或以本作品为基础进行二次创作。但要求你:

    • 署名:应在使用本文档的全部或部分内容时候,注明原作者及来源信息。
    • 非商业性使用:不得用于商业出版或其他任何带有商业性质的行为。如需商业使用,请联系作者。
    • 相同方式共享的条件:在本文档基础上演绎、修改的作品,应当继续以知识共享署名 4.0国际许可协议进行许可。