支持事务,加锁开销大,加锁慢,会出现死锁,锁的粒度小,并发下等待锁的几率较低,因此支持高并发。html
手动测试行锁须要首先关闭自动提交,每一个会话都须要关闭自动提交mysql
mysql> SHOW VARIABLES LIKE 'autocommit'; #查看 mysql> SET autocommit = 0;
中间执行SQLsql
最后执行完了须要进行提交session
mysql> COMMIT;
步骤 | Session1 | Session2 |
1 | 能够查询innodb_lock表数据 | 能够查询innodb_lock表数据 |
2 | 能够增删改innodb_lock表数据 | 能够查询旧数据,增删改innodb_lock表数据阻塞 |
3 | commit | commit同时阻塞的增删改为功 |
4 | 能够增删改innodb_lock表数据 | 增删改innodb_lock表与Session1不一样行数据也阻塞 |
5 | commit | commit同时阻塞的增删改为功 |
6 | 没能获取session2更新的数据 | commit |
7 | 能够查询innodb_lock表更新后数据 |
这里有几个问题:并发
表名:innodb_lock高并发
步骤 | Session1 | Session2 |
1 | CREATE INDEX idx_id ON innodb_lock(id); | |
2 | COMMIT; | |
3 | UPDATE innodb_lock SET color = 'pink' WHERE id = 1; | UPDATE innodb_lock SET color = 'yellow' WHERE id = 2; |
4 | COMMIT; | COMMIT; |
在这里两个session能够同时更新数据,实现行锁。咱们能够看出这个索引落在WHERE语句参数的ID上,假如没有WHERE 条件而且没有索引是否也可成功?测试
步骤 | Session1 | Session2 |
1 | DROP INDEX idx_id ON innodb_lock; | |
2 | COMMIT; | |
3 | UPDATE innodb_lock SET color = 'red' WHERE id = 1; | UPDATE innodb_lock SET color = 'black'; |
4 | COMMIT; | COMMIT; |
在第3行session2发生阻塞,由于没有索引则会发生阻塞。spa
这种锁方式也是MySQL实现悲观锁的方式3d
mysql> BEGIN; mysql> SELECT ... FOR UPDATE;
在中间进行数据更新code
mysql> COMMIT;
最后进行提交。
一、仍是innodb_lock这张表和数据,自动提交开启的状况和没有索引的实践手动锁定记录。
步骤 | Session1 | Session2 |
1 | BEGIN; | |
2 | SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE; | UPDATE innodb_lock SET color = 'orange' WHERE id = 1; #阻塞 |
3 | UPDATE innodb_lock SET color = 'pink' WHERE id = 1; | |
4 | COMMIT; | #阻塞释放,执行更新,数据被覆盖为orange |
二、上一个测试两个session修改的是同一条数据,若是修改不同的数据,是否还会发生阻塞
步骤 | Session1 | Session2 |
1 | BEGIN; | |
2 | SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE; | UPDATE innodb_lock SET color = 'yellow' WHERE id = 2; #阻塞 |
3 | UPDATE innodb_lock SET color = 'red' WHERE id = 1; | |
4 | COMMIT; | #阻塞释放,执行更新 |
三、这里能够看到session1对数据表进行了锁表,那咱们给id加上索引是否就不会阻塞
步骤 | Session1 | Session2 |
1 | CREATE INDEX idx_id ON innodb_lock(id); | |
2 | BEGIN; | |
3 | SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE; | UPDATE innodb_lock SET color = 'blue' WHERE id = 2; #未阻塞 |
4 | UPDATE innodb_lock SET color = 'pink' WHERE id = 1; | |
5 | COMMIT; |
四、session2未发生阻塞,那么假如锁定的行与更新的行不是一个行那session2能更新哪行呢
步骤 | Session1 | Session2 |
1 | BEGIN; | |
2 | SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE; | |
3 | UPDATE innodb_lock SET color = 'yellow' WHERE id = 2; | UPDATE innodb_lock SET color = 'red' WHERE id = 1; #阻塞 |
4 | UPDATE innodb_lock SET color = 'orange' WHERE id = 2; #阻塞 | |
5 | UPDATE innodb_lock SET color = 'grey' WHERE id = 3; #未阻塞 | |
6 | COMMIT; |
五、咱们发现id为1和2的两行都被锁住了,若是这样的话是否是说明只要是锁定或更新的行都会被锁
步骤 | Session1 | Session2 |
1 | INSERT INTO innodb_lock VALUES(4, 'red'),(5, 'orange'); | |
1 | BEGIN; | |
2 | SELECT * FROM innodb_lock WHERE id < 3 FOR UPDATE; | |
3 | UPDATE innodb_lock SET color = 'black' WHERE id > 3; | UPDATE innodb_lock SET color = 'black' WHERE id = 1; #阻塞 |
4 | UPDATE innodb_lock SET color = 'black' WHERE id = 2; #阻塞 | |
5 | UPDATE innodb_lock SET color = 'black' WHERE id = 3; #阻塞 | |
6 | UPDATE innodb_lock SET color = 'black' WHERE id = 4; #阻塞 | |
7 | UPDATE innodb_lock SET color = 'black' WHERE id = 5; #阻塞 | |
8 | COMMIT; |
六、不会吧,所有阻塞了,id为3的数据明明没在锁住和更新的数据里,这是为何呢?咱们再试一组数据。
步骤 | Session1 | Session2 |
1 | INSERT INTO innodb_lock VALUES(6, 'purple'),(7, 'white'); | |
2 | BEGIN; | |
3 | SELECT * FROM innodb_lock WHERE id < 3 FOR UPDATE; | |
4 | UPDATE innodb_lock SET color = 'black' WHERE id > 5; | UPDATE innodb_lock SET color = 'black' WHERE id = 2; #阻塞 |
5 | UPDATE innodb_lock SET color = 'black' WHERE id = 3; #阻塞 | |
6 | UPDATE innodb_lock SET color = 'black' WHERE id = 4; #未阻塞 | |
7 | UPDATE innodb_lock SET color = 'black' WHERE id = 5; #未阻塞 | |
8 | UPDATE innodb_lock SET color = 'black' WHERE id = 6; #阻塞 | |
9 | INSERT INTO innodb_lock VALUES(8, 'test'); #阻塞 | |
10 | COMMIT; |
我再添加两条数据,我知道的颜色单词就这些了,多一个也想不起来了。
我嘞个去,结果让人匪夷所思,小于号是后妈养的吗?为何3就阻塞而5就不阻塞。
好吧,算你厉害,你们仍是记住这个结果吧。
这里这种范围的锁定就是传说中的间隙锁,他有一种特色就是只要在范围以内的数据所有被锁住,无论当前是否存在。
七、若是有两张innodb的表,两个session锁住各一张表,而后再去更新对方的那张表会怎样呢?
步骤 | Session1 | Session2 |
1 | BEGIN; | BEGIN; |
2 | SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE; | SELECT * FROM innodb_test WHERE id = 1 FOR UPDATE; |
3 | UPDATE innodb_test SET color = 'pink' WHERE id = 1; #阻塞 | UPDATE innodb_lock SET color = 'pink' WHERE id = 1; #阻塞 |
4 | COMMIT; |
在第3行都发生了阻塞,而在Session2的第3行出现如下错误
这里出现了传说中的死锁,就是两个session吃着本身碗里的还看着对方碗里的,双方还都是倔脾气,就在这里杠上了,谁也不服谁。
本文索引关键字:
间隙锁:http://www.cnblogs.com/huanStephen/p/8076172.html#c_lock
悲观锁:http://www.cnblogs.com/huanStephen/p/8076172.html#p_lock
死锁:http://www.cnblogs.com/huanStephen/p/8076172.html#d_lock
欢迎你们索引!