mysql中的锁

全局锁

什么是全局锁

就是对整个数据库加锁,使整个数据库只能进行读操作,这时其他操作,都会被阻塞

使用全局锁的命令:

flush tables with read lock

释放全局锁的命令:

unlock tables

全局锁什么时候使用:

全局锁主要应用于全局逻辑备份,就是在数据库备份期间使用,用于避免出现因为数据或表结构的更新,而出现备份文件的数据与预期的不一样

使用全局锁会带来什么缺点:

如果数据库里有很多数据,备份就会花费很多的时间,关键是备份期间,业务只能读数据,而不能更新数据,这样会造成业务停滞

既然备份数据库数据的时候,使用全局锁会影响业务,那有什么其他方式可以避免?

有的,如果数据库的引擎支持的事务支持可重复读的隔离级别,那么在备份数据库之前先开启事务,会先创建 Read View,然后整个事务执行期间都在用这个 Read View,而且由于 MVCC 的支持,备份期间业务依然可以对数据进行更新操作。

因为在可重复读的隔离级别下,即使其他事务更新了表的数据,也不会影响备份数据库时的 Read View,这就是事务四大特性中的隔离性,这样备份期间备份的数据一直是在开启事务时的数据

表级锁

mysql中表级锁有以下四种

表锁:

元数据锁(MDL):

意向锁:

AUTO-INC锁:

表锁:

什么是表锁:

表锁就是对数据库中的某张表进行加锁 ,且有两种表锁,第一种就是共享锁(也称读锁),第二种就是独占锁(也称写锁),需要注意的点是,表锁除了会限制别的线程读写外,还会限制本线程接下来的读写操作

如何使用:

使用共享锁: lock tables 表名 read;

使用独占锁:lock tables 表名 write;

两种锁的释放方式相同:unlock tables ;

关闭加锁的线程时也会同时关闭锁

表锁的作用:

表锁是数据库并发控制的重要机制,它通过限制对表的并发访问来维护数据的一致性

表锁的缺点:

因为表锁的颗粒度太大,会影响并发性能。

元数据锁:

什么是元数据锁:

元数据锁,不需要显示调用,因为我们对数据库表进行操作时,会自动给表加上元数据锁,元数据锁有两种

一种是对表进行CRUD(就是增删改查操作),加的是MDL读锁

一种是对表做结构变更操作的时候,加的是MDL写锁

元数据锁的作用:

MDL是为了保证当用户对表执行CRUD操作时,防止其他线程对这个表结构做了变更。

举例:

当有线程在执行select语句(加MDL读锁)的期间,如果有其他线程要更改该表的结构(申请MDL读锁),那么将会被阻塞,直到执行完select语句(释放MDL读锁)

反之当有线程对表结构进行变更(加MDL读锁)的期间,如果有其他线程执行了CRUD操作(申请MDL读锁),那么就会被阻塞,直到表结构变更完成(释放MDL写锁)

注意点:

MDL不需要显示调用,MDL是在事务提交后才会释放,在事务执行期间,MDL是一直持有的

申请MDL锁的操作会形成一个队列,队列种写锁获取优先级高于读锁,一旦出现MDL写锁等待,会阻塞后续该表的所有CRUD操作

意向锁(暂时不太清除)

什么是意向锁:

意向锁是数据库中用于实现层次化锁定协议的一种锁机制。它们InnoDB存储引擎特有的锁类型,用于表示打算在某个数据项上加锁,但尚未实际加锁的状态.意向锁的存在使得数据库

系统能够有效的管理不同层级的锁定操作,同时保证锁的兼容性和一致性

意向锁的作用:

意向共享锁和意向独占锁都是表级锁,不会和行级锁的共享锁和独占锁发生冲突,而意向锁之间也不会发生冲突,只会和共享表锁和独占表锁发生冲突。

表锁和行锁是满足读读共享,读写互斥,写写互斥

AUTO-INC锁

什么是AUTO-INC锁

表里面的主键通常都会设置成自增的,这是通过对主键字段声明AUTO-INCREMENT属性实现的。AUTO-INC锁是特殊的表锁机制,锁不是再一个事务提交后才释放,而是在执行完插入语句后就会立即释放

在插入数据时,会加一个表级别的AUTO-INC锁,等插入语句执行完成后,才会把AUTO-INC锁释。

缺点:

那么,一个事务在持有AUTO-INC锁的过程中,其他事务的如果要向该表插入语句都会被阻塞,从而保证插入数据时,被AUTO-INCREMENT修饰的字段值是连续递增的。

但是,AUTO-INC锁再对大量数据进行插入的时候,会影响插入性能,因为另一个事务中的插入会被阻塞。

解决办法:

在mysql5.1.22版本开始,InooDB存储引擎提供了一种轻量级的锁来实现自增。

工作时间,都是在插入数据时,都是为被AUTO_INCREMENT修饰的字段加锁,但是锁的释放时间不同,轻量级的锁,在为该字段(被AUTO_INCREMENT修饰的字段)

赋值一个自增的值,就把这个轻量级锁释放了,而不需要等待整个插入语句执行完后才释放锁

如何选择使用轻量级锁还是AUTO-INC 锁:

InnoDB存储引擎提供了个innodb_autonic_lock_mode的系统变量,用来控制

innodb_autoinc_lock_mode =0,就采用AUTO-INC锁,语句执行结束后才释放;

innodb_autoinc_lock_mode =2,就采用轻量级锁,申请自增主键后就释放锁,不需要等待语句执行后才释放

innodb_autoinc_lock_mode=1:

普通insert 语句,自增锁在申请之后就马上释放;

类似insert .....select 这样的批量插入数据的语句,自增锁还是要等语句结束后才被释放

当 innodb_autoinc_lock_mode = 2 是性能最高的方式,但是当搭配 binlog 的日志格式是 statement 一起使用的时候,在「主从复制的场景」中会发生数据不一致的问题

举个例子,考虑下面场景:

session A 往表 t 中插入了 4 行数据,然后创建了一个相同结构的表 t2,然后两个 session 同时执行向表 t2 中插入数据。

如果 innodb_autoinc_lock_mode = 2,意味着「申请自增主键后就释放锁,不必等插入语句执行完」。那么就可能出现这样的情况:

  • session B 先插入了两个记录,(1,1,1)、(2,2,2);
  • 然后,session A 来申请自增 id 得到 id=3,插入了(3,5,5);
  • 之后,session B 继续执行,插入两条记录 (4,3,3)、 (5,4,4)。

可以看到,session B 的 insert 语句,生成的 id 不连续。

行级锁

分为三类:

Record Lock ,记录锁,也就是仅仅把一条记录锁上

Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身

Next-Key Lock:Record Lock+Gap Lock的组合,锁定一个范围,并且锁定记录本身

Record Lock

Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有S锁和X锁之分的:

当一个事务对一条记录加了S型记录锁后,其他事务也可以继续对该记录加S型锁记录(s型和s锁兼容),但是不可以对该记录加x型记录锁

当一个事务对一条记录加了X型记录锁后,其他事务即不可以对该记录加s型锁记录(s型与x锁不兼容),也不可以对该记录加x型记录锁(x型与x锁不兼容)

举个例子,当一个事务执行了下面这条语句:

mysql > begin; mysql > select * from t_test where id = 1 for update;

就是对 t_test 表中主键 id 为 1 的这条记录加上 X 型的记录锁,这样其他事务就无法对这条记录进行修改了。

当事务执行 commit 后,事务过程中生成的锁都会被释放。

Gap Lock

Gap Lock称为间隙锁,只存在于重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。

间隙锁虽然存在x型间隙锁和s型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻读记录而提出的

Next-Key Lock

Next-Key Lock称为临建锁,是Record Lock +Gap Lock的组合,锁定一个范围,并且锁定记录本身

Mysql是怎么加行级锁的?

什么sql语句会加行级锁:

普通的select语句是不会对记录加锁的(除了串行化隔离级别),因为它属于快照读,是通过MVCC(多版本并发控制)实现的。

如果要在查询时对记录加行级锁,可以使用下面这两个方式,这两种查询会加锁的语句称为锁定读

//对读取的记录加共享锁(S型锁) select ... lock in share mode; //对读取的记录加独占锁(X型锁) select ... for update;

事务提交,锁就释放了

还有update和delete操作都会加行级锁,且锁的类型都是独占锁(X型锁)

//对操作的记录加独占锁(X型锁) update table .... where id = 1; //对操作的记录加独占锁(X型锁) delete from table where id = 1;

行级锁有哪些种类

行级锁的种类在不同的隔离级别下,是不同的

在读已提交隔离界别下,行级锁的种类只有记录锁

在可重复读隔离级别下,行级锁的种类除了有记录锁,还有间隙锁(目的是为了避免幻读),所以行级锁

的种类主要有三类:

  • Record Lock,记录锁,也就是仅仅把一条记录锁上;
  • Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身;
  • Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

MySQL是如何加行级锁的

行级锁的加锁规则比较复杂,不同的场景,加锁的形式是不同的。

加锁对象是索引,加锁的基本单位是next-key lock

在能使用记录锁或者间隙锁就能避免幻读现象的场景下,next-key lock就会退化成记录锁或间隙锁

唯一索引等值查询

使用唯一索引进行等值查询的时候,查询记录不存在,加锁的规则也会不同,下面的例子是使用的主键索引

当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会退化成「记录锁」。

当查询的记录是「不存在」的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的 next-key lock 会退化成「间隙锁」

唯一索引范围查询

当唯一索引进行范围查询时,会对每一个扫描到的索引加next-key锁,然后如果遇到下面这些情况,会退化成记录锁或间隙锁

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MySQL(Locking)用于控制并发访问数据库资源以避免数据一致性问题。MySQL支持多种类型的,这些可以分为以下几类: 1. **共享(Shared Locks, S)**: - 允许读取数据,但阻止其他事务对同一行进行写操作。如果多用户同时请求共享,则所有请求都会立即获得。 ```sql SELECT * FROM table WHERE id = 1; -- 获取S ``` 2. **排他(Exclusive Locks, X)**: - 只允许一个事务独占一行,阻止其他事务进行读取或写入操作。 ```sql INSERT INTO table VALUES (1, 'value'); -- 获取X UPDATE table SET column = 'new_value' WHERE id = 1; -- 获取X DELETE FROM table WHERE id = 1; -- 获取X ``` 3. **意向(InnoDB Only, IX)**: - InnoDB存储引擎特有的,用于定表级,允许事务定整个表以便在其范围内进行插入或删除操作。 ```sql LOCK TABLES table WRITE; -- 获取IX ``` 4. **行级乐观(Row-Level Optimistic Locking, ROWX)**: - MySQL的默认行为是行级定,但可以通过`SELECT ... FOR UPDATE`语句实现乐观,它会检查行的版本号是否与先前读取时一致。 5. **死(Deadlocks)**: - 当两个或更多的事务因等待对方释放资源而互相阻塞时,就会发生死。 6. **自旋(Spin Locks)**: - 这不是MySQL的标准机制,而是某些库或优化策略使用的高级概念,它让进程在获取失败时循环尝试,直到成功。 了解这些的类型有助于管理和优化并发性能,尤其是在高并发环境下。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值