MySQL事务相关笔记

01 Apr 2015

ACID

当人们提到数据库事务的特性时, 总会提到ACID. 但是ACID是描述性的词语, 究竟什么是ACID, 缺少严格的定义. 所以我们在说事务要满足ACID特性时, 总觉得再说, 我们要科学发展, 但什么才是科学的, 却模糊不清.

我理解, ACID应该是一个模糊的需求描述, 难以下严格的定义. 具体

事务, 解决的问题以及概念 (接地气的解释?)

SQL标准中, 列出了事务操作中存在的几种现象:

根据上述三种现象, SQL标准划分出下述四种隔离级别:

另外, 没有覆盖在SQL标准里面, 但是经常出现的问题:

写丢失 (Lost Update) 与 游标稳定 (Cursor Stability)

如果语句话就能将逻辑表达清楚的, 则不存在写丢失的问题.

update salary set pay = pay + 100 where id = 123;

因为, 在更新时已经将该行锁住.

而当使用外部逻辑(或者存储过程), 都会存在这样的问题.

Cursor Stability 就是为了解决写丢失.

Snapshot isolation

每个事务, 在自己的一个数据版本上操作, 因此读永远不会阻塞. 每个数据都有一个版本. 写的时候, 只有当所有的数据版本不变时, 才会写入, 否则提交失败. 第一个提交的人赢!

##

使用了共读锁, 但是需要的是独占锁. 即每个事务看起来不是一个一个顺序执行完成的. 需要读写锁.

粒度: READ-UNCOMMITTED < READ-COMMITTED < Cursor Stability < REPEATABLE-READ < SERIALIZABLE.

对于MySQL隔离级别的说明

在默认的 REPEATABLE-READ 模式下:

TODO: next key locking

事务的实现

不同级别事务, 通过不同粒度的锁来实现.

也需要读写锁, 因为有可能在某一时刻, 从读锁转换为写锁. 在为转换成写锁前, 还是可以和其他读锁共存的.

写锁会阻塞读锁, 典型的 Reader / Writer 问题.

悲观锁 乐观锁 的概念

乐观锁的基本思路: CAS

MVCC (multi-version concurrency control)

通过多个版本数据并存, 每个事务操作一个版本的数据, 从而提高并发. 在合并的时候解决冲突.

类比版本控制git的执行方式, 每个分支上开发, 这样大家单独开发, 提高了效率. 相当于如果没有监测到冲突就自动合并. 不过严格对比起来, 应当说每个开发这在本次提交里面看到的文件, 其他提交者都没修改.

前提是关注点不一样, 冲突很少的情况下才可以.

实现

PostgreSQL: 存每个版本的数据. InnoDb: 只保留最新版本数据, 但是旧版本数据可以通过日志回溯得到. 所以导致的一个问题就是, 如果一个事务过长的话, 会导致undo log 太多 ???

[mvcc-survey]

加锁

根据条件加锁, 如果有索引可以对索引加锁, 否则需要对全表加锁 ???

预先加锁

select … from … where …

对索引的启示

查询条件是否使用索引影响到是行锁还是表锁.

参考

HOME