十八、锁

行级锁

InnoDB中实现的就是行级锁(row-level lock)
实现了事务之间的隔离功能
除了行级锁还有间隙锁gap、下键锁next-lock

什么是行级锁?
对某行数据进行修改时会锁住该行数据防止被其他人操作直至该行数据操作被提交后才解锁。
什么时间隙锁,下键锁?
对某行数据操作时,不止会锁定该行数据还会锁定该行数据的一定范围,使之不能被其他人操作称为间隙锁。
对某行数据操作时,会锁定该行数据即其后续行称为下键锁。

#当autocommit设置为0时,即关闭自动提交事务。
mysql> select @@autocommit;                         
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)

在不同会话中更新同一行语句时,第二个会话会卡住,因为第一个会话开启了事务并未自动提交,这种现象称为行锁等待。

默认50s不提交会自动回滚此次事务。

隔离级别

MySQL的四种隔离级别
RU: 读未提交的数据,读取脏页(即内存中的数据),一般业务中不允许出现
RC: 读已提交的数据,会出现不可重复读(每次读取的数据不一样),即幻读,但可防止脏读.
RR: 默认级别,可重复读的数据,可能有幻读现象,利用的是undo的快照技术+GAP(间隙锁)+NextLock(下键锁)来实现防止幻读。
SR: 可串行化,即一个事务完成并提交后才能执行下一个事务,可以防止死锁,但是并发事务性能较差

补充: 在RC级别下,可以减轻GAP+NextLock锁的问题,但是会出现幻读现象,一般在为了读一致性会在正常select后添加for update语句。但是执行完语句一定要commit否则容易出现锁等待。

#查询隔离级别,默认RR级别
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.11 sec)

#修改配置文件方式改隔离级别为RU级别
$ vim /etc/my.cnf
[mysqld]
...
transaction_isolation=read-uncommitted
#除此之外transaction_isolation参数还有
#read-committed(RC级别)
#REPEATABLE-READ(RR级别)

$ /etc/init.d/mysqld restart

使用RU隔离模式,左侧会话窗口更改数据后,还未提交该事务时右侧会话窗口就能查询到修改后的数据,此时读到的是内存中的脏数据,故不可在业务中出现。

修改为RC级别,左边会话窗口中每次commit提交后都能在右边会话中读取到修改后的数据,这种情况在金融业务中是不允许出现,因为多次commit提交,每次查询都是最新修改后的数据,可能一秒之中数据变化多次,不能进行精确数据统计。

修改为RR级别,即默认级别时,在左边会话中修改并提交事务后,在右边会话中的数据并未修改,需要手工执行commit命令或者断开会话再重连才会查询到修改后的数据。

这种方式使用的MVCC机制(多版本并发控制),每开启一个窗口就会生成一个undo快照,每次读取都是原始的数据而不是其他窗口修改后的数据。

RC的幻读现象,右边会话中将id>2的name都修改为zs,此时左边会话正好插入一条新数据id=6跟7的数据并提交事务,接着右边窗口提交事务后发现id=6跟7的数据并未修改为zs

此时通过RR模式的两把锁,即GAP(间隙锁)+NextLock(下键锁)来实现防止幻读,锁定表中id>2的数据防止修改或插入新的数据。

注意:GAP跟NextLock锁只会锁索引键值,故where的条件列必须是索引列。

RR模式幻读现象,左侧会话中插入id为4值为m6的数据并提交,右侧此时是RR模式看不见第四行数据,除非手动执行commit或者断开会话重连才能看见;但此时右侧也添加一行数据id为4值为m6时就会报错。

为了防止此次幻读现象,也可以在查询语句后接for update语句锁表

此时左侧会话会卡住不能执行修改表操作


学习来自:郭老师博客,老男孩深标DBA课程 第五章

posted @ 2021-03-05 20:53  努力吧阿团  阅读(56)  评论(0编辑  收藏  举报