mysql的锁介绍

从共享性上来说,mysql的数据库锁分为:

        共享锁(读锁):lock in share mode;一个事务获取了读锁之后,不排斥其他事务读数据,但排斥其他事务增删改。

        排它锁(写锁):for update;一个事务获取了写锁之后,排斥其他事务增删改查。

共享锁:

select * from test_table where age>60 lock in share mode;

排它锁:

select * from test_table where age>60 for update;

       根据锁的对象的不同,可以将锁分为表锁和行锁。顾名思义,表锁是加在表上的锁,而行锁是加在数据行的上的锁。

表锁

       mysql的MyISAM引擎就是使用的表锁。MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

        表锁不会出现死锁,发生锁冲突几率高,并发低。所以MyISAM不适合做写为主表的引擎,因为写锁后,其它线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。

行锁

       行锁会出现死锁,发生锁冲突几率低,并发高。

       MySQL的InnoDB引擎支持行锁。与Oracle不同,MySQL的行锁是通过索引加载的,也就是说,行锁是加在索引响应的行上的。如果执行的SQL语句没有通过索引方式,则会全表扫描,行锁则无法实现。取而代之的是表锁,此时其它事务无法对当前表进行更新或插入操作。

       也就是说。假设操作A在更新时,由于是通过非主键或索引选中的,升级为为表级锁,这时候A占有锁,这时候操作B则无法对该表进行更新或插入操作,因为它获取不到锁只有当A提交事务后,B才会成功执行。

      在一条select语句后加上for update,则查询到的数据会被加上一条排它锁,其它事务可以读取,但不能进行更新和插入操作。

行锁的实现需要注意:

  1. 行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。

  2. 两个事务不能锁同一个索引。

  3. insert,delete,update在事务中都会自动默认加上排它锁。

行锁场景:

A用户购买物品,service层先查询该物品数量,若数量足够,则进行后续的减操作;这种情况查询的时候应该对该记录进行加锁。否则,B用户在A用户查询后购买前先一步将物品买走,而此时A用户已经进行了物品数量是否足够的判断,则可能会出现物品数量已经不足但却购买成功的情况。为了避免此情况,需要在A用户操作该记录的时候进行for update加锁。

间隙锁
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内并不存在的记录,叫做间隙。

InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁。

例如:

-- 用户A
update test_table set count=8 where id>2 and id<6
-- 用户B
update test_table set count=10 where id=5;

      这个过程中,假设 id在1-到6之间即便是没有5。这时A操作是占有锁的,且锁对这个不存在的id=5这个数据也加了锁,所以B是无法进行更新的,只能等A提交事务之后,B才能修改。

行级锁定的优点:
·         当在许多线程中访问不同的行时只存在少量锁定冲突。
·         回滚时只有少量的更改。
·         可以长时间锁定单一的行。

行级锁定的缺点:
·         比页级或表级锁定占用更多的内存。
·         当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。
·         如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。
·         用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行。

你可能感兴趣的:(sql,1024程序员节,mysql)