MySQL中的锁

MySQL中的锁

锁是计算机协调多个线程并发访问某一资源的机制。
在数据库中,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。

MySQL的锁机制比较简单,表锁由MySQL Server实现,行锁则是存储引擎各自实现,不同的引擎实现的方式不同。在MySQL的常用引擎中InnoDB支持行锁,而MyISAM则只能使用MySQL Server提供的表锁。

几种常见锁的比较:

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 页面锁(cap锁,间隙锁):开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

MyISAM的表锁

MySQL的表级锁有两种模式:

  • 表共享读锁(Table Read Lock)
  • 表独占写锁(Table Write Lock)

给表加共享读锁语法:lock table 表名 read

给表加独占写锁语法:lock table 表名 write

例1:演示表共享读锁。

sql session1 session2
lock table testmyisam read;
select * from testmyisam; 成功 成功
select * from testmyisam s; Table ‘s’ was not locked with LOCK TABLES 成功
select * from emp; Table ‘emp’ was not locked with LOCK TABLES 成功
insert into testmyisam value(2); Table ‘testmyisam’ was locked with a READ lock and can’t be updated 等待执行
unlock tables; 插入成功

例2:演示表独占写锁。

sql session1 session2
lock table testmyisam write;
select * from testmyisam; 成功 等待
select * from testmyisam s; Table ‘s’ was not locked with LOCK TABLES
select * from emp; Table ‘emp’ was not locked with LOCK TABLES
insert into testmyisam value(4); 成功
unlock tables; 查询成功

总结:

  • 对MyISAM表加了共享读锁,对于其他session,不会阻塞对同一个表的读请求,阻塞对同一个表的写请求;对于当前session,对同一个表的写请求会直接报错。
  • 一个session中只要使用了lock table加了表锁,不管是共享读锁还是独占写锁,在当前session中,对其他表或用表别名访问同一个表会直接报错。
  • 对MyISAM表加了独占写锁,对于其他session,对同一个表的所有请求都会阻塞;对于当前session,可以对同一个表进行CRUD。

InnoDB的行锁

InnoDB引擎支持行锁。行锁也有两种模式:

  • 共享锁(读锁):当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但不允许其进行写操作,也不允许其他事务给这几行上排它锁,但允许上读锁。

  • 排它锁(写锁):当一个事务对某几行上写锁时,不允许其他事务写,但允许读。更不允许其他事务给这几行上任何锁。包括写锁。

共享锁的写法:sql lock in share mode,例如:select * from 表 where 条件 lock in share mode;

排它锁的写法:sql for update,例如select * from 表 where 条件 for update;

例1:演示行锁。

sql session1 session2
begin;
select * from emp where empno=7369 lock in share mode;
select * from emp where empno=7369; 成功 成功
select * from emp where empno=7499; 成功 成功
select * from emp where empno=7369 lock in share mode;
update emp set ename=‘morris’ where empno=7369; 成功 等待
commit; 成功
begin;
select * from emp where empno=7369 for update;
select * from emp where empno=7369; 成功 成功
select * from emp where empno=7499; 成功 成功
commit;
begin;
update emp set ename=‘SMITH’ where ename=‘morris’; 成功 阻塞
commit; 更新成功

总结:

  • 行锁其实锁的是索引,所以行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。
  • 两个事务不能锁同一个索引。
  • insert 、delete 、update在事务中都会自动默认加上排它锁。

InnoDB的表锁

和MyISAM的表锁差别不大。注意开启一个新事务的时候会释放表锁。

更多精彩内容关注本人公众号:架构师升级之路
在这里插入图片描述

你可能感兴趣的:(MySQL,mysql,数据库,表锁,行锁,间隙锁)