美文网首页
MySql中的锁!

MySql中的锁!

作者: 全麦土司 | 来源:发表于2019-12-30 21:33 被阅读0次

只要是涉及多个线程共同访问某一资源的问题就一定会出现锁。

1、不同的存储引擎支持不同的锁机制,锁的特性可以大致归纳如下:

行锁 表锁
MyISam yes
InnoDB yes yes

2、锁的几种分类及其性质

  • 表锁:开销小,加锁快,不会死锁;锁定粒度大,发生锁冲突的概率比较高,并发度最低。
  • 行级锁:开销大,加锁慢,会出现死锁;锁定粒度小,发生锁冲突的概率比较低,并发度比较高。
  • 页级锁:开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定的粒度也介于上两者之间,并发度一般。

3、MyISAM的表锁

MyISAM的表级锁有两种模式:
   - 表共享读锁(Table Read Lock)
   - 表独占写锁(Table Write Lock)

MySql中锁的兼容性.png

3.1、MyISAM存储引擎写阻塞示例

session1 session2
获得file1的写锁定
lock table file1 write;
Query OK, 0 rows affected (0.00 sec)
当前Session对表的增改查都是可以执行的;
select * from file1 where id = 1;
insert into file1 values(1003,"Test");
update file1 set title= "Test" where id = 1
其他session对于锁定表的查询被阻塞,需要等待锁被释放;
select * from fiile1 where id = 1;
unlock tables;
释放锁
等待
获得锁,查询返回

        MyISAM在执行查询语句之前,会自动给涉及的所有表加读锁。在执行增删改操作之前,会自动给涉及的表加写锁,这个过程不需要用户的干预。因此,用户一般不需要显示加锁。
加锁一般就是为了模拟事务操作,实现对某一时间点的多个表的一致性的读取。例如,有一个订单表 orders,其中记录有各订单的总金额 total,同时还有一个订单明细表 order_detail,其中记录有各订单每一产品的金额小计 subtotal,假设我们需要检查这两个表的金额合计是否相符,可能就需要执行如下两条 SQL:

Select sum(total) from orders;
Select sum(subtotal) from order_detail;

        这时,如果不先给两个表加锁,就可能产生错误的结果,因为第一条语句执行过程中,order_detail 表可能已经发生了改变。因此,正确的方法应该是:

Lock tables orders read local, order_detail read local;
Select sum(total) from orders;
Select sum(subtotal) from order_detail;
Unlock tables;

一个 session 使用 LOCK TABLE 命令给表 film_text 加了读锁,这个 session 可以查询锁定表中的记录,但更新或访问其他表都会提示错误;同时,另外一个session 可以查询表中的记录,但更新就会出现锁等待。

session1 session2
获得表 film_text 的 READ 锁定;
lock table film_text read;
当前 session 可以查询该表记录;
select film_id,title from film_text where film_id = 1001;
其他 session 也可以查询该表的记录;
mysql> select film_id,title from film_text where film_id = 1001;
当前 session 不能查询没有锁定的表;
mysql> select film_id,title from film where film_id = 1001;
(错误)
其他 session 可以查询或者更新未锁定的表 mysql> select film_id,title from film where
当前 session 中插入或者更新锁定的表都会提示错误:
mysql> insert into film_text (film_id,title)values(1002,'Test');
ERROR
其他 session 更新锁定表会等待获得锁:
mysql> update film_text set title = 'Test' where film_id = 1001;
等待
释放锁
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
等待
Session 获得锁,更新操作完成:
mysql> update film_text set title = 'Test' where film_id = 1001;
Query OK, 1 row affected (1 min 0.71 sec)Rows matched: 1 Changed: 1 Warnings: 0

还要注意别名的问题,假如有如下所示的表actor

//获得读锁
lock table actor read;
//通过别名进行访问就会出现错误
select a.first_name,a.last_name actor a;(!!!出现错误)
//需要对别名进行锁定
lock table actor as a read,actor as b read;
//在进行查询就会成功了。

4、InnoDB的锁

  • 共享锁:允许一个事务去读一行,组织其他事务获得相同数据集的排他锁。
  • 排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享锁和排他锁。


    InnoDB共享锁示例.png

        对于 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。
InnoDB排他锁示例.png

相关文章

网友评论

      本文标题:MySql中的锁!

      本文链接:https://www.haomeiwen.com/subject/hfamoctx.html