Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL 数据库锁

MySQL 数据库锁的实现

作者:Java-阿旭

本文主要介绍了MySQL 数据库锁的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

数据库事务-锁机制

1.什么是锁

锁,其实就是一个内存种的结构,在事务还没有来之前是没有锁存在的。在事务未开始前只有一条记录,是没有锁和记录之间的关联关系的。

锁结构种有很多的信息,主要的有两个:

当一条事务想要对某条记录进行改动时,就会生成一把锁,在生成锁的时候,会去检查该条记录有没有被其他的锁关联。① 如果没有,is_wating就是false,不需要等待,此时表示事务上锁成功,可以进行后续操作;② 如果有其他事务上锁,则is_wating就是true,加锁失败,需要等待其他事务释放锁,才能后续操作该记录。

2.锁解决的问题

数据库锁主要解决并发情况下,数据隔离问题。数据库是可以有多个客户端连接并访问的,这种情况就会有并发操作同一数据记录的情况。因此数据库出现了锁机制,解决各种并发情况下出现的隔离问题。

3.并发访问相同记录的几种情况

4.理解读锁和写锁

对于MySQL的innoDB存储引擎来说,读锁/写锁可以作用在表上,也可以作用在行上

4.1 读锁

读锁(S)也称共享锁,在多个事务共同读同一个记录时,是可以同时读取,互不影响,互不干扰的。
在进行SELECT查询操作的时候,可以使用读锁,使多个任务之间可以共同读取同一条记录。但在查询操作时,也可以使用写锁,后面讲写锁的时候再说。
如何在读取的时候加锁:

SELECT * FROM student LOCK IN SHARE MODE;
#或者
SELECT * FROM student FOR SHARE;#(mysql 8.0新写法)

4.2 写锁

写锁(X)也称排他锁,在事务在进行写操作时,会上X锁,导致当前事务未完成写操作时,其他事务的读/写会被阻塞。保证在同一个时间内,只有一个事务能对事务进行读/写操作。

SELECT * FROM student FOR UPDATE;

进行写操作时,会自动给该条记录加X锁。写记录:INSERT\DELETE\UPDATE 4.3 读锁和写锁的兼容情况

读写

5.表锁

表锁是指给所操作的整张表进行加锁,相对行锁,对表加锁的颗粒度比较大,因此它的开销也比较小。由于是对整张数据表进行加锁,因此可以避免死锁的出现。即使这样,是对整张表进行加锁,就会导致大量的事务无法继续操作表,所有表锁的性能是较差的。
在MySQL中,InnoDB提供了表锁行锁由于表锁的性能比较差,一般我们都很少用到表锁。只有特殊场景下会用到表锁,比如:数据崩溃恢复。

5.1 表级的读/写锁

查看有那些表被加锁:

SHOW OPEN TABLES;
#或者
SHOW OPEN TABLES WHERE In_use >0;

手动给表加锁:

LOCK TABLES student READ;#给student表加S锁
LOCK TABLES stdent WRITE;#给student表加X锁

释放锁:

UNLOCK TABLES;

小结

5.2 意向锁

MySQL的InnoDB存储引擎中,支持表锁和行锁同时存在,而意向锁就是表锁的一种。

意向锁是为了协调表锁行锁同时共存而存在的。意向锁是一中不于行锁冲突的表级锁。意向锁用户是无法手动添加的,它是InnoDB存储引擎自动给加的。当在给某个行添加S锁或X锁时,需要先获取当前行所在表的意向锁。

意向锁分为两种:

理解意向锁的意义:当没有意向锁的时候,当事务想要给表加表锁的时候,需要去检测每行记录是否加有锁,这样每条检测的效率非常的低。意向锁的出现,很好的解决这种情况。有意向锁后,事务要表添加锁,只要检查当前表是否有意向锁就可以了。

总结:意向锁之间是互相兼容的和读写锁不兼容:

6.行锁

行锁就是给表中的某条记录上把锁,将该条记录锁住。行锁是在InnoDB存储引擎层实现的,这是InnoDB与MyISAM最大的区别之一。行锁是粒度小的,发生锁冲突的概率很小,因此会实现高并发的效果,但是因粒度较小,加锁较慢,会出现死锁的情况

6.1 记录锁

记录锁就是一把行锁,顾名思义,给某条记录上锁。

6.2 间隙锁

间隙锁是在某个记录前的间隙加入一个锁,这样就使该记录前面的间隙是不能添加数据的。这种间隙锁有效的防止了幻读的出现。间隙锁的出现,也是为了解决幻读而提出来的。
不管是共享锁还是排他锁,起到的作用是一样的,
举例:

select * from student where id=11 for update;

此时id为18加了间隙锁

这种会出现一个问题,因为间隙锁只会锁住行前面的间隙,那么,如果此时给id为25后面的间隙插入数据,就会有问题,此时,数据库做了两个提供了两个伪记录: Infimum记录,表示该页面中最小的记录。 Supremun记录,表示该页面中最大的记录。
加入如下,就可以阻止其他事务加入(25,+∞)的数据了。

select * from student where id > 20 lock in share mode;

间隙锁的出现,会发生死锁,如下:

当记录中存在间隙锁时,有其他事务想在这个间隙插入数据,由于锁的存在,会阻止插入,让事务进行等待,知道释放间隙锁。此时内存中会生成一个插入意向锁,这个意向锁是一种间隙锁,并不是表锁中的意向锁。这种插入意向锁可以有多个,一个间隙中有多个插入意向锁并不冲突,插入意向锁之间不会有排斥。

6.3 临界锁

临界锁是用来补充上面说的间隙锁,因为间隙锁只是锁住了记录前面的间隙,但是并不包含自己,因此临界锁就出现了,临界锁就是记录锁和间隙锁的组合体。

select * from student where id <=18 and id > 10 for update;

7.悲观锁和乐观锁

悲观锁、乐观锁其实并不是一种锁,而是一中并发下锁的一种设计思想

7.1 悲观锁

7.2 乐观锁

乐观锁,就是对数据的操作持有乐观的态度,任务每次操作数据时,都不会有其他的事务对数据进行修改操作。但是在每次一修改数据的时候,都会判断在此期间数据是否被其他事务修改过。

乐观锁是在操作数据的时候,通过程序来进行控制的,比如:使用版本号,或者时间戳来进行比对。

`UPDATE student SET name= '李四' ,version=version+1 WHERE version=version` 

乐观锁的适用场景读多写少的场景,由程序实现,不会出现死锁问题。

7.3 总结

到此这篇关于MySQL 数据库锁的实现的文章就介绍到这了,更多相关MySQL 数据库锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文