参考文章:https://blog.csdn.net/puhaiyang/article/details/72284702
一.mysql锁的结构图
如上图所示,针对mysql的innodb存储引擎,mysql锁包括了乐观锁和悲观锁。而悲观锁又包括共享锁和排它锁,共享锁/排它锁里又有行锁和表锁的实现,下面一个个说明他们的内容。
二.锁详解
1.乐观锁
乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。
通常实现是这样的:在表中的数据进行操作时(更新),先给数据表加一个版本(version)字段,每操作一次,将那条记录的版本号加1。然后update的时候,where子句里,增加version值的判断,如果update返回的值是0,说明是版本号冲突,如果是1,则更新成功。
举个例子,例如要更新一个用户的数据
(1)查出用户的数据(假设根据uid查询),sql为:select id,name,mobile,version from user_db.t_user_info where uid=1024;
假设查出来的数据为
(2)假设要更新name字段为lisi,则sql为:update user_db.t_user_info set name='lisi',version=4 where uid=1024 and version=3;
如果这时候更新的结果是1,则更新成功;如果为0,则需要用户重新操作
2.悲观锁
悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,这点跟java中的synchronized很相似,所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。
mysql的悲观锁包括共享锁和排它锁。
先简单介绍什么是共享锁和排它锁:共享锁指的就是对于多个不同的事务,对同一个资源共享同一个锁;而排它锁与共享锁相对应,就是指对于多个不同的事务,对同一个资源只能有一把锁。
举个简单形象的例子来说明一下:共享锁就像是你家的大门钥匙,除了你有,你家人也有;而排它锁则像是试衣间,我进来了别人就不能进来了。
再来说说什么是行锁和表锁。
顾名思义,行锁获取数据库某一行的锁,而表锁就是获取某张表的锁。
下面更详细说明他们的用法。
(1)共享锁
刚刚说了,对于悲观锁,一般数据库已经实现了,共享锁也属于悲观锁的一种,所以,mysql自身对共享锁的功能是有实现的。
A.对于共享锁来说,一个事务获取了某一行的共享锁,则其他事务还可以继续获取这一行的共享锁,但是不能获取这行的排它锁。
B.如何获取某一行/表的共享锁。在select语句后面加 lock in share mode,即可获取共享锁。例如,sql为:
begin;
SELECT * from city where id = "1" lock in share mode;
C.值得注意的一点,在有事务获取了共享锁之后,其他事务是不能做insert/update/delete,因为insert/update/delete语句,是自动加上排它锁的
D.如何判断获取的是行锁还是表锁
SELECT * from city where id = "1" lock in share mode; 这个sql里,如果id这个字段带了索引,则获取的是行锁,否则获取的是表锁
ps:共享锁又称读锁
(2)排它锁
mysql自身对排它锁的功能也是有实现的
A.对于排它锁来说,一个事务获取了某一行的共享锁,其他事务不能再获取任何锁(包括共享锁和排它锁)
B.如何获取某一行/表的排它锁。在select语句后面加 for update,即可获取排它锁。例如,sql为:
begin;SELECT * from city where id = "1" lock in share mode;
C.如何判断获取的是行锁还是表锁和共享锁是一样的
D.insert/update/delete语句,是自动加上排它锁的
ps:排它锁又称写锁
(3)行锁
行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。
(4)表锁
表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。
关于行锁和表锁,前面在共享锁和排它锁里已有说明,这里只提一点,慎用表锁,即select for update语句,where子句务必带上索引,否则极容易造成性能问题