操作类型
读锁(共享锁S)
写锁(排他锁X)
数据操作粒度
其他锁
乐观锁
概念
实现方式
(1)CAS
(2)增加版本字段
悲观锁
不同存储引擎的锁
MyISAM(表锁)
读锁
写锁
InnoDB(行锁)
特点
MyISAM的使用
1.操作
加锁:locak table 表1 read/write ,表2 read/write ,...
释放锁(所有):unlock tables ;
查看哪些表加了锁
分析锁的严重程度
Table_locks_immediate :即可能获取到的锁数,即立刻能加锁的表数 Table_locks_waited:需要等待的表锁数(如果该值越大,说明存在越大的 锁竞争) 一般建议: Table_locks_immediate/Table_locks_waited > 5000, 建议采用InnoDB引擎,否则MyISAM引擎
2.锁的调度问题
MyISAM存储引擎的读锁和写锁是互斥的,就是串行的,但是当一个请求请求表的写锁,另一个请求请求表的读锁,此时引擎会优先写锁,哪怕在锁等待队列中读锁先于写锁等待,此时也会优先写锁,因为MyISAM认为写更重要,所以MyISAM不适用于大量写的场景,因为此时会导致读等待过长或读不到
当然这是可以设置的:
高并发问题
MyISAM也允许通过参数的设置来调节写的时候数据的插入
当concurrent_insert设置为NEVER(0)时,不允许并发插入。 当concurrent_insert设置为AUTO(1)时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置。 当concurrent_insert设置为ALWAYS(2)时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。
InnoDB的行锁
对于InnoDB表,本文主要讨论了以下几项内容: (1)InnoDB的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。 (2)介绍了InnoDB间隙锁(Next-key)机制,以及InnoDB使用间隙锁的原因。 在不同的隔离级别下,InnoDB的锁机制和一致性读策略不同
1.与MyISAM最大的不同
查看锁的竞争情况
show status like 'innodb_row_lock%';
如果发现锁争用比较严重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比较高,还可以通过设置InnoDB Monitors来进一步观察发生锁冲突的表、数据行等,并分析锁争用的原因
2事务概念
3.事务并发带来的问题
4.四种隔离级别的加锁情况
(1)读未提交:而读未提交隔离级别是不加锁的,所以它的性能是最好的,没有加锁、解锁带来的性能开销
(2)读已提交:每个 select 语句都有自己的一份快照,而不是一个事务一份,所以在不同的时刻,查询出来的数据可能是不一致的,所以说RC级别下的快照是每个select都一份,而RR情景下是事务中第一个select开始就会读取快照,持续在整个事务期间内,
(3)可重复读:通过快照(MVCC + undolog)的形式,可重复读是在事务开始的时候生成一个当前事务全局性的快照,而读已提交则是每次执行语句的时候都重新生成一次快照
(4)串行化:将事务的执行变为顺序执行,与其他三个隔离级别相比,它就相当于单线程,后一个事务的执行必须等待前一个事务结束
5.无索引问题
加锁的过程要分有索引和无索引两种情况,比如下面这条语句
update user set age=11 where id = 1 id 是这张表的主键,是有索引的情况,那么 MySQL 直接就在索引数中找到了这行数据,然后干净利落的加上行锁就可以了。 而下面这条语句 update user set age=11 where age=10 表中并没有为 age 字段设置索引,所以, MySQL 无法直接定位到这行数据。那怎么办呢,当然也不是加表锁了。MySQL 会为这张表中所有行加行锁,没错,是所有行。但是呢,在加上行锁后,MySQL 会进行一遍过滤,发现不满足的行就释放锁,最终只留下符合条件的行。虽然最终只为符合条件的行加了锁,但是这一锁一释放的过程对性能也是影响极大的。所以,如果是大表的话,建议合理设计索引,如果真的出现这种情况,那很难保证并发度。
6.意向共享锁和意向排它锁
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁
7.InnoDB的锁兼容性列表
如果一个事务请求的锁模式与当前的锁兼容,InnoDB就请求的锁授予该事务;反之,如果两者两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁
8.什么时候使用表锁
(1)事务需要更新表的大部分数据、表又比较大,这个时候使用行锁会比较耗费性能并导致事务执行时间较长
(2)事务涉及的表比较多,容易导致死锁且造成大量事务回滚
使用注意
(1)Lock table虽然可以给InnoDB加表级锁,但是表锁不是属于存储引擎进行管理,而是由上一层MySQL server进行管理。仅当autocommit=0、innodb_table_lock=1(默认设置)时,InnoDB层才能知道MySQL加的表锁,这种情况下,InnoDB才能自动识别涉及表级锁的死锁;否则,InnoDB将无法自动检测并处理这种死锁
(2)在用LOCAK TABLES对InnoDB锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCAK TABLES释放表锁,因为UNLOCK TABLES会隐含地提交事务;COMMIT或ROLLBACK产不能释放用LOCAK TABLES加的表级锁,必须用UNLOCK TABLES释放表锁,正确的方式见如下语句
SET AUTOCOMMIT=0; LOCAK TABLES t1 WRITE, t2 READ, ...; [do something with tables t1 and here]; COMMIT; UNLOCK TABLES;
9.关于死锁
不同存储引擎下的死锁
死锁的常用方法
如果出现死锁,可以用SHOW INNODB STATUS命令来确定最后一个死锁产生的原因和改进措施。
如何排查死锁:
SELECT * FROM information_schema.innodb_trx:查找当前运行中的事务,根据状态定位到当前阻塞的锁id
SELECT * FROM information_schema.innodb_trx
间隙锁
next-key lock概念:
危害
生效原则
锁的优化
如何锁定一行
https://blog.csdn.net/qq_44766883/article/details/105879308
Update your browser to view this website correctly. Update my browser now
×