mysql-3-锁

Mysql中有哪几种锁?

MyISAM和MEMORY采用表级锁(table-level locking)

BDB采用页面锁(page-level locking)或表级锁,默认为页面锁

InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

这也是为什么现在业务喜欢选用InnoDB的原因之一


按照对数据的锁定范围分,可以分为 行级锁、表级锁、页级锁、间隙锁

行级锁

行级锁是mysql中锁定粒度最细的一种锁。表示只针对当前操作的行进行加锁。
行级锁能大大减少数据库操作的冲突,其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁

开销大,加锁慢,会出现死锁。发生锁冲突的概率最低,并发度也最高。

行锁在 InnoDB 中是基于索引实现的,所以一旦某个加锁操作没有使用索引,那么该锁就会退化为表锁

InnoDB有三种行锁的算法:

Record Lock(记录锁):即元数据锁,单个行记录上的锁。这个也是我们日常认为的行锁。

Gap Lock(间隙锁):间隙锁,锁定一个范围,但不包括记录本身
(只不过它的锁粒度比记录锁的锁整行更大一些,他是锁住了某个范围内的多个行,包括根本不存在的数据)。
GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。该锁只会在隔离级别是可重复度或者以上的级别内存在。间隙锁的目的是为了让其他事务无法在间隙中新增数据。

间隙锁示例:
事务A执行SELECT ※ FROM t WHERE id BETWEEN 2 AND 4 FOR UPDATE,InnoDB会锁定记录2和4之间的间隙,即锁定范围(2, 4)。
在事务A提交之前,事务B不能在该间隙内插入新记录,如插入id=3的记录。
如果数据的id分别为 1 4 5 则(2 AND 4)锁住的区间为(1,4) 因为基于索引建锁 没有数据无法建立
再入id 1 10 20 (5 and 15)锁住的区间为(1,10)U(10,20)

间隙锁只锁insert语句

Next-Key Lock(临键锁):它是记录锁和间隙锁的结合,锁定一个范围,并且锁定记录本身。
对于行的查询,都是采用该方法,主要目的是解决幻读的问题。next-key锁是InnoDB默认的锁
(]左开右闭 右边的数据行会被锁住

举个例子:
id age name
1 10 Lee
3 24 Soraka
5 32 Zed
7 45 Talon

该表中 age 列潜在的临键锁有:
(-∞, 10],
(10, 24],
(24, 32],
(32, 45],
(45, +∞],

在事务 A 中执行如下命令:

1
2
3
4
-- 根据非唯一索引列 UPDATE 某条记录
UPDATE table SET name = Vladimir WHERE age = 24;
-- 或根据非唯一索引列 锁住某条记录
SELECT * FROM table WHERE age = 24 FOR UPDATE;

很明显,事务 A 在对 age 为 24 的列进行 UPDATE 操作的同时,也获取了 (24, 32] 这个区间内的临键锁。

事务 B 中执行以下命令,则该命令会被阻塞:

1
INSERT INTO table VALUES(100, 26, 'Ezreal');

那最终我们就可以得知,在根据非唯一索引 对记录行进行 UPDATE \ FOR UPDATE \ LOCK IN SHARE MODE 操作时,InnoDB 会获取该记录行的 临键锁 ,并同时获取该记录行下一个区间的间隙锁。

即事务 A在执行了上述的 SQL 后,最终被锁住的记录区间为 (10, 32)。

上面这三种锁都是排它锁(X锁)

表级锁

表级锁是mysql中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分mysql引擎支持。
最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)

开销小,加锁快,不会出现死锁。发生锁冲突的概率最高,并发度也最低。

页级锁

页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。
表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折中的页级锁,一次锁定相邻的一组记录。BDB 支持页级锁。

开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。


按照锁的共享策略来分:共享锁、排他锁、意向共享锁、意向排他锁

共享锁和排他锁在MySQL中具体的实现就是读锁和写锁:

读锁(共享锁):Shared Locks(S锁)

针对同一份数据,多个读操作可以同时进行而不会互相影响

写锁(排它锁):Exclusive Locks(X锁)

当前写操作没有完成前,它会阻断其他写锁和读锁
注:没有索引的情况下加X锁 会锁住整张表
例如select . from student where lore = ‘123’ for update;
由于lore没有索引 加锁之后 会锁住整张表 student表不允许再加任何其他锁

innodb中 insert update delete会为涉及的数据自动加锁

以下这两种锁不常见:

IS锁:意向共享锁、Intention Shared Lock

当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁。

IX锁:意向排他锁、Intention Exclusive Lock

当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁。


从加锁策略上分:乐观锁和悲观锁

乐观锁:

认为对于同一个数据的并发操作,是不会发生修改的(或者增删改少,查多)
是通过程序实现的,一般使用版本号或者时间戳

悲观锁:

悲观的认为,不加锁的并发操作一定会出问题。哪怕没有修改,也会认为修改。
因此对于同一个数据的并发操作,悲观锁采取加锁的形式。
悲观锁又分为表级锁和行级锁,套娃~可以看一下上面的。


自己理解:

mysql中拿到锁对象的应该是事务 java中synchronized拿到锁对象的是线程