1.锁的分类
全局锁:对整个数据库实例进行加锁,Flush tables with read lock (FTWRL),(set global readonly=true)之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。
全局锁的典型使用场景是,做全库逻辑备份。
但是让整库都只读,听上去就很危险:
如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
如果你在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,会导致主从延迟。
一致性读是好,但前提是引擎要支持这个隔离级别
官方自带的逻辑备份工具是mysqldump。当mysqldump使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是可以正常更新的。
2.表级锁
表锁:
lock table read/write unlock tables
也可以在客户端断开连接的时候释放锁,事务提交时并不会释放表锁,但是unlock table会释放锁,事务也会自动提交。
特点:
1.当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。
2.在用LOCK TABLES 给表显式加表锁时,必须同时取得所有涉及到表的锁,并且 MySQL 不 支持锁升级(不能访问其他表,持有读锁,只能读取)
Myisam特点:
1.MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作 (UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁.
2.MyISAM表也支持查询和插入操作的并发进行.
concurrent_insert=0 不允许并发插入
concurrent_insert=1 如果MyISAM表中没有空洞(即表的中间没有被删除的 行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL 的默认设置。
concurrent_insert=2 允许并发插入
3.锁调度:即使读请求先到锁等待队列,写请求后到,写锁也会插 到读锁请求之前。不适用于大量的更新操作和查询应用的。
MDL(元数据锁)
加锁:当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。
释放锁:事务结束后自动释放。
如何进行online DDL?
3.行锁(innodb)
S : lock in share mode
X: for update
UPDATE、DELETE 和 INSERT 语句,InnoDB 会自动给涉及数据集加排他锁(X);对于普通 SELECT 语句,InnoDB 不会加任何锁
事务结束后自动释放。
实现方式: InnoDB 行锁是通过给索引上的索引项加锁来实现的,只有通过 索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁。只有通过 索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁
两阶段协议:在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
4.间隙锁(innodb)
解决幻读?
幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
1.在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。
2.上面session B的修改结果,被session A之后的select语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。
什么是间隙锁:
产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB只好引入新的锁,也就是间隙锁(Gap Lock)。顾名思义,间隙锁,锁的就是两个值之间的空隙
加锁规则:
https://blog.csdn.net/xmtblog/article/details/92470543
死锁:
当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。
1.一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置。
2.另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑。