一、事务的基本要素(ACID)

1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。undo log 日志

2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。

3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。MVCC和间隙锁

4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚 redo log。

二、事务隔离级别

事务隔离级别 脏读 不可重复读 幻读
读未提交 ru
不可重复读 rc
可重复读 rr
串行化

三、事务的并发问题

  • 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。

  • 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

    小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

四、当前读和快照读

快照读: 一般的 select * from …. where … 语句都是快照读 快照读通过mvcc实现 当前读: 当前读,会在搜索的时候加锁

select * from .... where  ... for update
select * from .... where  ... lock in share mode
update .... set .. where ...
delete from. . where ..

当前读通过 next key lock 避免幻读 如果事务中都使用快照读,那么就不会产生幻读现象,但是快照读和当前读混用就会产生幻读。

五、MVCC版本控制

1、MVCC:多版本并发控制,是针对快照读的一种不通过锁来保证事务可见性的实现方式,主要是通过Innodb的undo log和一致性试图(read view)实现的。

2、Mysql会在某一时刻,创建一致性视图(read view实现的),RR隔离级别是在事务开始时刻,确切地说是第一个读操作创建read view的;RC隔离级别是在语句开始时刻创建read view的。我理解这个一致性试图是当前活跃的事务的id数组。

3、undo log 主要是回滚用的,我们知道每次新增或者修改一条数据,都会产生一条undo log,我们可以理解为是历史数据的记录,或者是对当前操作的反向记录。在我们的每条记录中,数据库都会给我们增加三个字段,id、事务id、回滚指针,我们对一条数据的操作,通过回滚指针,会将数据的undo log形成一条数据链。

4、在我们在遍历undo log链的时候,比较这条undo log链数据的事务id,如果事务id小于记录的最小的事务id,那么这条数据对当前事务是可见的,如果大于记录的最大事务id,那么这条数据对当前事务是不可见的,如果事务id落在了两者之间,那么需要判断是不是被记录了。如果被记录了,说明不可见。

通过high/low water mark快速判断:
trx_id < view->up_limit_id的记录对于当前read view是一定可见的;
trx_id >= view->low_limit_id的记录对于当前read view是一定不可见的;
如果trx_id落在[up_limit_id, low_limit_id),需要在活跃读写事务数组查找trx_id是否存在,如果存在,记录对于当前read view是不可见

六、LBCC基于锁的控制

只使用唯一索引查询,并且只锁定一条记录时,innoDB会使用行锁。

只使用唯一索引查询,但是检索条件是范围检索,或者是唯一检索然而检索结果不存在时,会产生 Next-Key Lock。

使用普通索引检索时,不管是何种查询,只要加锁,都会产生间隙锁。

同时使用唯一索引和普通索引时,由于数据行是优先根据普通索引排序,再根据唯一索引排序,所以也会产生间隙锁。

锁住普通索引,会锁住对应的唯一索引的行。