LiangShang/liangshang.github.com

数据库的一些知识

Opened this issue · 0 comments

数据库事务的隔离级别

uncommitted read: 一个事务可能读到另一个事务尚未提交的修改,会导致 dirty read
unrepeatable read: 为了解决脏读,规定一个事物执行过程中的修改在提交前对其他事务不可见。但是这时一个事务在执行中读取某个数据两次。在这两次之间另一个事务将这个数据进行修改导致两次读的结果不一样。会导致 unrepeatable read。
repeatable read: 为了解决不可重复读,可以让事务锁定在读的行,这样其它事务不能修改。但是其它事务可以插入新的行并且这些行包含在事务接下来的读取中。这样会导致 phantom read。在InnoDB里因为行锁的 “GAP” 的存在,可以解决幻读的问题。
serializable: 最高的隔离级别,串行化并发的事务。解决了幻读的问题但是性能不好。

ACID

A atomic 事务里的所有操作要么都执行成功,要么都执行失败。
C consistency 事务前和事务后数据库的完整性约束没有发生变化
I isolation 数据库的隔离性(也就是不同的隔离级别)
D duration 事务一旦提交了结果就是永久性的,即使发生了宕机也不会消失掉。

行锁和表锁

InnoDB支持了行锁。只有走索引的时候才会去锁住行,否则会锁住表。锁住行准确的说是锁住了对应的索引。可能会导致死锁。
行锁包括读锁和写锁,也叫共享锁和排它锁。
InnoDB还提供了两种意向锁,都是表锁。在获取读(写)锁是必须先获得读(写)意向锁。

UPDATE INSERT DELETE 都会加排它锁。
SELECT * FOR UPDATE 会加排它锁
SELECT * LOCK IN SHARE MODE 会加共享锁。

两段锁协议

MySQL 加锁和释放锁是遵循两段式的协议的。也就是加锁阶段和释放锁阶段。加锁阶段就是逐步加锁,释放锁阶段就是一起释放。同时释放锁的阶段不能再加锁。

乐观锁、悲观锁和MVCC

悲观锁是数据库的锁机制(读锁和写锁)。总是假定数据会被别的事务修改所以加锁来保证。
乐观锁的加锁机制更轻松。一般是通过增加版本号来实现的。在读出数据的时候连版本号一起读出来。更新数据时将版本号加一。提交时会将新数据的版本号和数据库的版本号进行比对。只有新数据的版本号更大时才会更新成功。好处就是读不加锁。

MVCC的实现
MVCC会对数据的每一行增加一个版本号。这个版本号是事务的版本号。每开启一个新的事务。版本号都会加一。
在 repeatable read 的隔离级别下:
select 时会取出版本号小于等于这个事务版本号的值并删掉版本号为空或版本号大于事务版本号的数据。
INSERT 和 DELETE 时会将当前版本号写入
UPDATE 实质上是 一次 INSERT 和一次 DELETE。
所以读是快照读。也就是读的是snapshot 历史数据。可以不用加锁。但是去处理当前(最新)数据时还是要加锁的。

ACID 的实现

实现ACID的关键技术就是锁和日志。

A redo 和 undo 日志。
C 通过类型检查、唯一索引、外键约束和级联更新保护数据的完整性
I 加锁
D 磁盘持久化