写代码啦
MySQL的锁与事务
回复数(0) 浏览数(30)
{{topic.upvote_count || 0}} 编辑 回复

MyISAM和InnoDB锁区别

MyISAM默认行级锁,不支持表级锁
InnoDB都支持
这里我们假设X为排他锁,S为共享锁
共享锁和排他锁的兼容性 共享锁和排他锁的兼容性
对于MyISAM来说,比较适合的场景是
- 适合频繁执行全表count语句,因为在MyISAM中保存着变量整个表的行数,执行语句时候,可以直接读出来。
- 读操作频繁,写操作少的场景。
- 没有事务的场景

对于InnoDB适合的场景
- 数据库增删查改比较频繁
- 可靠性要求比较高

实现乐观锁的方式有两种,一种是使用时间戳来实现,一种是使用数据版本来实现。

数据库事务的四大特性

  • 原子性(Atomic)
    事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据修改操作要么全部执行,要么完全不执行。
  • 一致性(Consistency)
    在一个事务执行之前和执行之后数据库都必须处于一致性状态。
  • 隔离性(Isolation)
    一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。
  • 持久性(Durability)
    一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的

事务隔离级别以及并发访问问题

事务并发访问引起的问题以及如何避免
- 更新丢失
在MySQL所有事务隔离级别下均可以避免。
- 脏读
如果一个事务中对数据进行了更新,但事务还没有提交,另一个事务可以“看到”该事务没有提交的更新结果。READ-COMMITED事务隔离级别可以避免。
- 不可重复读
不可重复读取是指同一个事务在整个事务过程中对同一笔数据进行读取,每次读取结果都不同。REPEATABLE-READ事务隔离级别以上可避免。
- 幻读
幻读是指同样一笔查询在整个事务过程中多次执行后,查询所得的结果集是不一样的。SERIALIZABLE事务隔离级别可避免。

InnoDB可重复读隔离级别下如何避免幻读

表象
快照读,非阻塞读,基于伪MVCC来避免幻行。
内在
next-key锁(行锁+gap锁)

当前读和快照读
  • 当前读
    select ……lock in share mode, select……for update update,delete insert
  • 快照读
    不加锁非阻塞读

RR和RC级别下InnoDB的非阻塞读的实现

DB_TRX_ID,标识最近一行对本行记录的事务ID
DB_ROLL_PTR 回滚指针,写入回滚段,保存该行记录被更新之前的信息的指针,指向undo日志对应的地址。
DB_ROW_ID 行号,随着行插入而单调递增的行ID的值。没有主键和唯一键的话,Innodb就会为我们生成一个隐藏逐渐,即DB_ROW_ID。

undo日志
undo日志 undo日志

  • read view
    当我们去执行快照读,会为数据创建出来一个readview,来决定当前事务能看到的是那个版本的诗句。这个readview可能是最新版本,也可能是undo日志中的其他版本。这里遵循一个可见性算法,大概实现机制是,拿到当前修改数据的DB_TRX_ID,与当前活跃事务ID做对比,如果大于等于活跃事务ID,就从undo日志中取,直到小于活跃事务ID。即展示当前最稳定的版本。

RC和RR级别下的非阻塞读,区别就是RC的快照读,每次都会生成一个新的快照。而RR级别下的快照会生成read view,将当前系统中活跃的事务记录起来。每次都显示同一个readview。

至于为什么实现的是伪MVCC,是因为MVCC是多版本控制的,而对于RR级别的快照读下的undo日志,它的版本控制使用指针连接的串行化。

在RR下避免幻读的真正原因

真正的原因是next-key锁(行锁+gap锁)

1.行锁

对单个行记录上锁

2.gap锁

gap就是索引树中插入新记录的空隙的锁。
- 对主键索引或者唯一索引会用gap锁吗?
如果where条件全部命中,则不会加gap锁,只会加记录锁。
如果where条件全部不命中,或者部分命中,则会加gap锁。
- Gap锁会在非唯一索引或者不走索引的当前读中

Suppose that an index contains the values 10, 11, 13, and 20. The possible next-key locks for this index cover the following intervals, where a round bracket denotes exclusion of the interval endpoint and a square bracket denotes inclusion of the endpoint: 
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

官方文档中,我们可以看到gap锁的加锁范围。

  • 不走索引
    当前读不走索引,就会对当前的gap上锁,相当于锁表。

MyISAM和InnoDB锁区别

MyISAM默认行级锁,不支持表级锁
InnoDB都支持
这里我们假设X为排他锁,S为共享锁
共享锁和排他锁的兼容性 共享锁和排他锁的兼容性
对于MyISAM来说,比较适合的场景是
- 适合频繁执行全表count语句,因为在MyISAM中保存着变量整个表的行数,执行语句时候,可以直接读出来。
- 读操作频繁,写操作少的场景。
- 没有事务的场景

对于InnoDB适合的场景
- 数据库增删查改比较频繁
- 可靠性要求比较高

实现乐观锁的方式有两种,一种是使用时间戳来实现,一种是使用数据版本来实现。

数据库事务的四大特性

  • 原子性(Atomic)
    事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据修改操作要么全部执行,要么完全不执行。
  • 一致性(Consistency)
    在一个事务执行之前和执行之后数据库都必须处于一致性状态。
  • 隔离性(Isolation)
    一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。
  • 持久性(Durability)
    一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的

事务隔离级别以及并发访问问题

事务并发访问引起的问题以及如何避免
- 更新丢失
在MySQL所有事务隔离级别下均可以避免。
- 脏读
如果一个事务中对数据进行了更新,但事务还没有提交,另一个事务可以“看到”该事务没有提交的更新结果。READ-COMMITED事务隔离级别可以避免。
- 不可重复读
不可重复读取是指同一个事务在整个事务过程中对同一笔数据进行读取,每次读取结果都不同。REPEATABLE-READ事务隔离级别以上可避免。
- 幻读
幻读是指同样一笔查询在整个事务过程中多次执行后,查询所得的结果集是不一样的。SERIALIZABLE事务隔离级别可避免。

InnoDB可重复读隔离级别下如何避免幻读

表象
快照读,非阻塞读,基于伪MVCC来避免幻行。
内在
next-key锁(行锁+gap锁)

当前读和快照读
  • 当前读
    select ……lock in share mode, select……for update update,delete insert
  • 快照读
    不加锁非阻塞读

RR和RC级别下InnoDB的非阻塞读的实现

DB_TRX_ID,标识最近一行对本行记录的事务ID
DB_ROLL_PTR 回滚指针,写入回滚段,保存该行记录被更新之前的信息的指针,指向undo日志对应的地址。
DB_ROW_ID 行号,随着行插入而单调递增的行ID的值。没有主键和唯一键的话,Innodb就会为我们生成一个隐藏逐渐,即DB_ROW_ID。

undo日志
undo日志 undo日志

  • read view
    当我们去执行快照读,会为数据创建出来一个readview,来决定当前事务能看到的是那个版本的诗句。这个readview可能是最新版本,也可能是undo日志中的其他版本。这里遵循一个可见性算法,大概实现机制是,拿到当前修改数据的DB_TRX_ID,与当前活跃事务ID做对比,如果大于等于活跃事务ID,就从undo日志中取,直到小于活跃事务ID。即展示当前最稳定的版本。

RC和RR级别下的非阻塞读,区别就是RC的快照读,每次都会生成一个新的快照。而RR级别下的快照会生成read view,将当前系统中活跃的事务记录起来。每次都显示同一个readview。

至于为什么实现的是伪MVCC,是因为MVCC是多版本控制的,而对于RR级别的快照读下的undo日志,它的版本控制使用指针连接的串行化。

在RR下避免幻读的真正原因

真正的原因是next-key锁(行锁+gap锁)

1.行锁

对单个行记录上锁

2.gap锁

gap就是索引树中插入新记录的空隙的锁。
- 对主键索引或者唯一索引会用gap锁吗?
如果where条件全部命中,则不会加gap锁,只会加记录锁。
如果where条件全部不命中,或者部分命中,则会加gap锁。
- Gap锁会在非唯一索引或者不走索引的当前读中

Suppose that an index contains the values 10, 11, 13, and 20. The possible next-key locks for this index cover the following intervals, where a round bracket denotes exclusion of the interval endpoint and a square bracket denotes inclusion of the endpoint: 
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

官方文档中,我们可以看到gap锁的加锁范围。

  • 不走索引
    当前读不走索引,就会对当前的gap上锁,相当于锁表。
30
回复 编辑