安陆网站制作公司,招商加盟网站大全,外包seo服务收费标准,网络管理员正在设计新的无布局系列文章目录
【MySQL 流浪之旅】 第一讲 MySQL 安装【MySQL 流浪之旅】 第二讲 MySQL 基础操作【MySQL 流浪之旅】 第三讲 MySQL 基本工具【MySQL 流浪之旅】 第四讲 MySQL 逻辑备份【MySQL 流浪之旅】 第五讲 数据库设计的三个范式 目录
系列文章目录
一、什么是锁#x…系列文章目录
【MySQL 流浪之旅】 第一讲 MySQL 安装【MySQL 流浪之旅】 第二讲 MySQL 基础操作【MySQL 流浪之旅】 第三讲 MySQL 基本工具【MySQL 流浪之旅】 第四讲 MySQL 逻辑备份【MySQL 流浪之旅】 第五讲 数据库设计的三个范式 目录
系列文章目录
一、什么是锁
二、锁的类型
三、锁的算法
四、锁与事务隔离级别
4.1. 隔离级别简介
4.2. Read Uncommitted读取未提交内容
4.3. Read Committed读取提交内容
4.4. Repeatable Read可重读
4.5. Serializable可串行化
五、死锁 一、什么是锁
锁是实现事务隔离性最广泛使用的技术。以 MySQL InnoDB 为例数据库的锁有排他锁共享锁意向锁自增锁间隙锁。
按照粒度分为锁定整个表的表级锁table-level locking和锁定数据行的行级锁row-level locking
表级锁具有开销小、加锁快的特性但是表级锁的锁定粒度较大发生锁冲突的概率高支持的并发度低行级锁具有开销大加锁慢的特性但是行级锁的锁定粒度较小发生锁冲突的概率低支持的并发度高。
InnoDB 存储引擎同时支持行级锁row-level locking和表级锁table-level locking默认情况下采用行级锁。 InnoDB的行锁是实现在索引上的而不是锁在物理行记录上。所以如果访问没有命中索引就无法使用行锁将要退化为表锁共享行锁上升为共享表锁排他行锁上升为排他表锁。
二、锁的类型
InnoDB存储引擎实现的是行级锁
共享锁S Lock允许事务读一行数据排他锁X Lock允许事务删除或更新一行数据 排他锁和共享锁的兼容性 意向共享锁IS Lock事务想要获得一张表中某几行的共享锁意向排他锁IX Lock事务想要获得一张表中某几行的排他锁 意向排他锁和意向共享锁的兼容性 间隙锁where条件是一个范围时数据库会锁定区间数据主要是解决幻读问题。 自增锁自增锁是一种特殊的表级别锁table-level lock专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况如果一个事务正在往表中插入记录所有其他事务的插入必须等待以便第一个事务插入的行是连续的主键值。控制同一sql 语句插入的所有记录的自增id是连续的。
平时还有提到的悲观锁乐观锁在数据库层面上没有这个锁的概念如果要做简单映射悲观锁可以映射成排他锁乐观锁是由应用层面保障的和 DB 的锁概念无关。
乐观锁认为冲突概率低操作数据时不会锁定数据只有在提交修改时才检查。如果数据已被修改则回滚否则提交。 悲观锁一种并发控制方法。认为冲突概率高每次读写前都加锁。
所以我们说锁的分类从不同角度来看有不同的类型 三、锁的算法
Record Lock单个行记录上的锁Gap Lock间隙锁锁定一个范围但不包含基本本身Next-key LockGap Lock Record Lock锁定一个范围并且锁定记录本身
四、锁与事务隔离级别
4.1. 隔离级别简介
事务的隔离级别是用来描述并发控制机制中不同事务之间隔离程度的参数。以下是几种常见的隔离级别及其特点
Read Uncommitted读取未提交内容Read Committed读取提交内容Repeatable Read可重读Serializable可串行化
事务隔离级别脏读不可重复读幻读Read Uncommitted读取未提交内容是是是Read Committed读取提交内容否是是Repeatable Read可重读否否否Serializable可串行化否否否
4.2. Read Uncommitted读取未提交内容
定义所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用因为它的性能也不比其他级别好多少读取未提交的内容也称为脏读所以在该隔离级别下是存在脏读这种缺陷的。在该隔离级别是允许脏读。
锁的状态Read Uncommitted这个隔离级别是不加锁的所有的事物都能任意操作数据数据是没有任何一致性可言其实数据就是处于混乱的状态中。
图示 图中所示会导致什么问题呢
tab2在B时刻查询到了表的数据但是如果在C时刻发生了回滚那么tab1的数据的插入不成功的其实这时表里是没有数据的但是事务tab2却查询到了数据这就导致数据不一致了。
4.3. Read Committed读取提交内容
定义只能读取到已经提交的数据这是大多数数据库系统的默认隔离级别但不是MySQL默认的。它满足了隔离的简单定义一个事务只能看见已经提交事务所做的改变。这种隔离级别 会出现所谓的不可重复读Nonrepeatable Read这种缺陷因为同一事务的其他实例在该实例处理其间可能会有新的commit所以同一select可能返回不同结果。
锁的状态该隔离级别下数据的读取都是不加锁的但是事务的写入、修改、删除是加锁的。
4.4. Repeatable Read可重读
定义这是MySQL的默认事务隔离级别他确保一事务的多个会话在并发读取数据时会看到同样的数据行。 T1 T2 T3 begin; begin; begin; rootlocalhost select id,class_name,teacher_id from class_teacher; ------------------------------ | id | class_name | teacher_id | ------------------------------ | 1 | 初三一班 | 1| | 2 | 初三二班 | 1 | ------------------------------ 2 rows in set (0.00 sec) update class_teacher set class_name初三三班 where id1; Waiting…… rootlocalhost select id,class_name,teacher_id from class_teacher; ------------------------------ | id | class_name | teacher_id | ------------------------------ | 1 | 初三一班 | 1| | 2| 初三二班 | 1 | ------------------------------ 2 rows in set (0.00 sec) insert into class_teacher values (null,初三三班,1); commit; rootlocalhost select id,class_name,teacher_id from class_teacher; ------------------------------ | id | class_name | teacher_id | ------------------------------ | 1 | 初三一班 | 1| | 2 | 初三二班 | 1 | | 3 | 初三三班 | 1 | ------------------------------ 3 rows in set (0.00 sec)
从上图可以看出传统的Repeatable Read可重读为了保证可重读读取出来的数据行是加锁的所以这些行在commit锁释放前是不能修改的但是他不会对新插入的行加锁所以T3是可以插入数据的并且再次查询的时候就会看到新插入的的行这种现象就是幻读。
4.5. Serializable可串行化
定义这是最高的隔离级别它通过强制事务排序使之不可能相互冲突从而解决幻读问题。简言之它是在每个读的数据行上加上共享锁每次读都需要获得表级共享锁。在这个级别可能导致大量的超时现象和锁竞争读写相互都会阻塞。因此会导致大量的超时现象。
锁的状态MySQL从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读所有的读操作均为当前读读加读锁 (S锁)写加写锁 (X锁)。Serializable隔离级别下读写冲突因此并发度急剧下降在MySQL/InnoDB下不建议使用。
五、死锁
死锁是指两个或两个以上的事务在执行过程中因争夺锁资源而造成的一种互相等待的现象。
show engine innodb status查看死锁信息 死锁通常包括以下四个必要条件
互斥条件Mutual Exclusion每个资源只能同时被一个线程占用。如果一个线程占用了某个资源其他线程就无法同时占用它。请求与保持条件Hold and Wait线程在持有某些资源的同时又请求其他资源。如果线程在等待其他资源时不释放已占用的资源就可能导致死锁。不可剥夺条件No Preemption系统不能抢占线程占用的资源只能由线程自愿释放。循环等待条件Circular Wait多个线程之间形成一个环形等待其他线程释放资源的情况。
为了预防和解决死锁问题可以采取以下策略
加强互斥条件尽量减少共享资源的互斥性或者使用更高级的同步机制来替代基本的互斥锁。加强请求与保持条件要求数资源时尽量一次性请求所有需要的资源而不是逐个请求。加强不可剥夺条件允许操作系统抢占线程占用的资源以避免某些线程长时间占用资源而导致死锁。加强循环等待条件引入资源分配图检测潜在的死锁情况然后采取措施来打破等待环路。使用超时线程在等待资源时设置一个超时时间超时后可以放弃等待或者重试。使用死锁检测和恢复机制系统可以定期检测死锁并采取措施来解除死锁如终止某些线程或回滚操作。