mysql锁详解(死锁,表锁,行锁,页锁,共享锁,排他锁等)****
MySQL锁概述
锁是计算机协调多个进程或线程并发访问某一个资源的机制,在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所在有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
锁分类
死锁
1.什么是死锁
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进
2.产生死锁的必要条件
(1)互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源 (2)请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放 (3)不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
(4)环路等待条件:是指进程发生死锁后,必然存在一个进程–资源之间的环形链
3.处理死锁的基本方法
(1)预防死锁:通过设置一些限制条件,去破坏产生死锁的必要条件 (2)避免死锁:在资源分配过程中,使用某种方法避免系统进入不安全的状态,从而避免发生死锁 (3)检测死锁:允许死锁的发生,但是通过系统的检测之后,采取一些措施,将死锁清除掉 (4)解除死锁:该方法与检测死锁配合使用
3.1死锁检测 Jstack命令
jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息。 Jstack工具可以用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
4.死锁示例
(1)创建表test,插入id为1跟2的两条数据
CREATE TABLE `test` (
`id` int(20) NOT NULL,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT INTO test VALUES (1,"tsst1")
INSERT INTO test VALUES (2,"tsst2")
(2)开启事务
for update 加锁
InnoDB引擎默认加的是行锁,但是当查询的条件没有携带主键,或者是这条数据不存在的时候就会改为表锁
-- session1
begin;
select * from test where id = 3 for update;
insert into test(id, name) values(3, "test3");
-- session2
begin;
select * from test where id = 4 for update;
insert into test(id, name) values(4, "test4");
条件id=3是不存在的,上面两个并发事务一定会发生死锁
锁的区间划分
1、间隙锁(Gap Locks) 2、临键锁(Next-key Locks)
锁的粒度划分
1、表级锁(Table-level lock) 2、行级锁(Record Locks) 3、页级锁
锁级别划分
1、共享锁(share lock,即S锁)
2、排它锁 / 独占锁(exclusive lock,即X锁) 3、意向锁
加锁方式分类
自动锁( Automatic Locks) 显示锁(LOCK TABLES )
六、锁的使用方式分类
乐观锁(Optimistic Lock) 悲观锁(Pessimistic Lock)
补充锁的使用
# 开启s锁/读锁/共享锁
BEGIN;
SELECT * FROM book lock in share mode;
COMMIT;
# 开启x锁/写锁/排他锁
BEGIN;
SELECT * FROM book for update;
COMMIT;
# mysq8 nawait有锁不等待
BEGIN;
SELECT * FROM book for update nawait;
# mysq8 有锁返回没有锁的数据行
BEGIN;
SELECT * FROM book for update skip locked;