MySQL学习(四)锁机制

  • 分类
    • 读锁(共享锁):对同一个数据,多个读操作可以同时进行,互不干扰
    • 写锁(互斥锁):如果当前写操作没有完毕,则无法进行其他的读操作、写操作
  • 操作范围
    • 表锁:一次性对一张表整体加锁。如myisam存储使用引擎,开销小,加锁快,无死锁;锁的范围大,容易发生锁冲突,并发低
    • 行锁:一次性对一条数据加锁。如innodb使用行锁,开销大,加锁满,容易死锁;锁的范围小,不易发生锁冲突,并发度高(很小概率,发生高并发问题、不可重复读,丢失更新等问题)
      • 间隙锁(next-key):值在范围内,但却不存在

此时表中没有id=7的数据
update linelock set name = 'x' wher id > 1 and id < 9;

加锁 lock table 表1 read/write,表2 read/write
查看加锁的表: show open tables;

1.加读锁

结论1:一个会话,对A表加了read锁,则该会话可以对A表进行读操作,不能进行写操作;且该会话不能对其他表进行读、写操作。(即如果给A表加了读锁,则当前会话只能对A表进行读操作)

结论2:会话0对A表加了锁,其他会话的操作:

  • 可以对其他表(A表以外的表)进行读、写操作
  • 对A表可以读,写-需要等待释放锁 unlocal tables;

2.加写锁

会话0: lock table tablename write;
总结1:当前会话可以对加了写锁的表,可以进行任何操作(增删改查);但是不能操作(增删改查)其他表.
总结2:对会话0加写锁的表,可以进行增删改查的前提是:等会话0释放写锁。

3.行锁分析

  1. 如果会话x对某条数据a进行DML操作(研究时,关闭了自动commit的情况下),则其他会话必须等待会话x结束事务(commit/rollback)后,才能对数据a进行DML操作
  2. 表锁是通过 unlock tables; ,也可以通过事务解锁,行锁是通过事务解锁。
  3. 如果没有索引/索引失效,则行锁会转为表锁
  4. 行锁:如果有where,则实际加锁的范围就是where后面的范围(不是实际的值 )
    show status like '%innodb_row_lock%';
    image
  • innodb_row_lock_current_waits; 当前正在等待锁的数量
  • innodb_row_lock_time; 等待总时长。从系统启动到现在一共等待的时间
  • innodb_row_lock_time_avg; 平均等待时长

如果发现锁争用比较严重,如InnoDB_row_lock_waitsInnoDB_row_lock_time_avg的值比较高

如果仅仅是查询数据,能否加锁?可以 for update:select * from linelock where id = 2 for update;

4.InnoDB锁问题

参考博客:https://www.cnblogs.com/jpfss/p/8890250.html
InnoDB和MyISAM最大不同有两点:一是支持事务;二是采用了行级锁

  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
  • 排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。另外,为了允许行锁和表锁共存,实现多粒度锁机制

InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。

  • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
  • 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
    image

如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁。

  • 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。
  • 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。

用SELECT ... IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT... FOR UPDATE方式获得排他锁。

5.InnoDB行锁实现方式

:通过索引上的索引项加锁来实现的。这种行锁特定意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。

原文地址:https://www.cnblogs.com/lhxBlogs/p/15660224.html