设为首页 收藏本站
查看: 705|回复: 0

[经验分享] mysql 行锁的实现

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-4-8 14:45:41 | 显示全部楼层 |阅读模式
mysql锁的方式根据隔离级别不同而不同,因为默认隔离级别为repeatable-read可重复读,我们普遍理解为mysql锁实现方式为行锁,行锁就是利用索引实现完成的,mysql的支持的隔离级别有四种,这网上很多介绍,平常用的最多的也就是read-committed和repeatable-read两个,今天就对这两个隔离级别下锁的实现做下对比

首先我们就用默认级别repeatable-read的隔离级别来做测试:

mysql> CREATE TABLE `t1` (
    ->   `id` int(11) NOT NULL AUTO_INCREMENT,
    ->   `age1` int(11) DEFAULT NULL,
    ->   `age2` int(11) DEFAULT NULL,
    ->   PRIMARY KEY (`id`),
    ->   KEY `age1` (`age1`)
    -> ) ENGINE=InnoDB;
mysql> select * from t1;
+----+------+------+
| id | age1 | age2 |
+----+------+------+
|  1 |    1 |    2 |
|  2 |    1 |    2 |
|  3 |    1 |    2 |
|  4 |    1 |    4 |
|  5 |    1 |    2 |
|  6 |    2 |    3 |
+----+------+------+

创建了一个表t1,插入了部分数据,建立了age1的辅助索引,现在开两个session来做测试:
session1session2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set age2=55 where age1=1 and id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql>  update t1 set age2=55 where age1=1 and id=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
rollbackrollback

看到这各位看官肯定觉得没问题,就应该是这样的啊,行锁嘛就是利用索引找到对应行进行加锁就好了,不急不急继续测试
session1session2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set age2=55 where age1=1 and age2=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set age2=55 where age1=1 and id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
rollbackrollback
咦.............这是咋回事呢?这更新的明显不是同一行为什么会被阻塞呢?我这暴脾气再用insert做下测试

session1session2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set age2=111 where age1=2 ;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1(age1,age2) values(1,33);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
rollbackrollback
..............插入数据和更新数据不是同一行业被阻塞了!好吧,来看下锁等待信息
mysql> select * from innodb_lock_waits \G;
*************************** 1. row ***************************
                wait_started: 2016-04-07 15:35:00
                    wait_age: 00:00:08
               wait_age_secs: 8
                locked_table: `sbtest`.`t1`
                locked_index: PRIMARY
                 locked_type: RECORD
              waiting_trx_id: 33333
         waiting_trx_started: 2016-04-07 15:35:00
             waiting_trx_age: 00:00:08
     waiting_trx_rows_locked: 1
   waiting_trx_rows_modified: 0
                 waiting_pid: 3
               waiting_query: update t1 set age2=55 where age1=1 and id=1
             waiting_lock_id: 33333:33:3:2
           waiting_lock_mode: X
   .....................................

为了节约版面后面截就删掉了,这是上面两个update不同行被阻塞时的记录

mysql> select * from innodb_lock_waits \G;
*************************** 1. row ***************************
                wait_started: 2016-04-07 15:40:43
                    wait_age: 00:00:26
               wait_age_secs: 26
                locked_table: `sbtest`.`t1`
                locked_index: age1
                 locked_type: RECORD
              waiting_trx_id: 33343
         waiting_trx_started: 2016-04-07 15:40:43
             waiting_trx_age: 00:00:26
     waiting_trx_rows_locked: 1
   waiting_trx_rows_modified: 1
                 waiting_pid: 3
               waiting_query: insert into t1(age1,age2) values(1,33)
             waiting_lock_id: 33343:33:4:7
           waiting_lock_mode: X,GAP
      .......................................
这个是insert时候的记录,第一个可以看出来是在等primary的X锁,但是根据记录我们可以查询出两个update的主键值应该是不同,session1查出来的id应该为4,session2直接指定的id为1,这明显不会一行啊,再来看看结合insert的锁等待情况,这个锁是在age1索引上,但是lock_mode多了一个GAP,这玩意是啥?好吧,只有挠着头皮去官方文档里找了,别问我为啥挠头,我不会告诉你我很爱汉字:
    Gap lock: This is a lock on a gap between index records, or a lock on the gap before the first or after the last index record.
    原来msyql有间隙锁机制,就是把两个记录直接的缝缝给锁住,又或者锁住前后记录,在repeatable-read隔离级别下的mysql会有一个间隙锁算法,假如进行update扫描时,辅助索引有多个记录满足条件是会把这几条记录及记录中间的缝缝都会锁住,而insert的时候也会去判断下一个记录是否有加锁,所以才会发生上面的阻塞。这是mysql为了保证该隔离级别下的可重复读的机制,但也影响到业务并发的效率,可以修改系统参数innodb_locks_unsafe_for_binlog=on就可以关闭改间隙锁机制。该值默认为off,修改事务隔离级别为read-committed也可以避免间隙锁。修改为read-committed来试试看。

mysql> set global tx_isolation='read-committed';
Query OK, 0 rows affected (0.00 sec)
全部session连接重新连接一下才能生效,现在来按上面的步骤再测试一下:
session1session2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set age2=55 where age1=1 and age2=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set age2=55 where age1=1 and id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
rollbackrollback
这个没问题..................

session1session2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set age2=111 where age1=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1(age1,age2) values(1,33);
Query OK, 1 row affected (0.00 sec)
rollbackrollback
也没问题..................

mysql在默认隔离级别repeatable-read下,会有gap lock和next-key lock两个算法锁来确保数据可重复读
Next-key lock: This is a combination of a record lock on the index record and a gap lock on the gap before the index record
next-key lock就是范围锁,当我们利用索引范围扫描时,在这一个范围内的数据都会被加锁,以防止幻读。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-201509-1-1.html 上篇帖子: mysql中的中文乱码处理 下篇帖子: mysql 之 版本升级,从5.5升级到5.7 mysql
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表