当数据库有并发事务的时候,可能会产生数据的不一致,这时候须要一些机制来保证访问的次序,锁机制就是这样的一个机制。算法
就像酒店的房间,若是你们随意进出,就会出现多人抢夺同一个房间的状况,而在房间上装上锁,申请到钥匙的人才能够入住而且将房间锁起来,其余人只有等他使用完毕才能够再次使用。
数据库
在Read Uncommitted级别下,读取数据不须要加共享锁,这样就不会跟被修改的数据上的排他锁冲突并发
在Read Committed级别下,读操做须要加共享锁,可是在语句执行完之后释放共享锁。分布式
在Repeatable Read级别下,读操做须要加共享锁,可是在事务提交以前并不释放共享锁,也就是必须等待事务执行完毕之后才释放共享锁。ide
SERIALIZABLE 是限制性最强的隔离级别,由于该级别锁定整个范围的键,并一直持有锁,直到事务完成。
性能
在关系型数据库中,能够按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。spa
MyISAM和InnoDB存储引擎使用的锁:设计
MyISAM采用表级锁(table-level locking)。orm
InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁。索引
行级锁,表级锁和页级锁对比
行级锁:MySQL中锁定粒度最细的一种锁,表示只针对当前操做的行进行加锁。行级锁能大大减小数据库操做的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。
特色:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。
表级锁:MySQL中锁定粒度最大的一种锁,表示对当前操做的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。
特色:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的几率最高,并发度最低。
页级锁:是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此取了折衷的页级,一次锁定相邻的一组记录。
特色:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常
从锁的类别上来说,有共享锁和排他锁。
共享锁: 又叫作读锁。当用户要进行数据的读取时,对数据加上共享锁。共享锁能够同时加上多个。
排他锁: 又叫作写锁,当用户要进行数据的写入时,对数据加上排他锁。排他锁只能够加一个,他和其余的排他锁,共享锁都相斥。
用上面的例子来讲就是用户的行为有两种,一种是来看房,多个用户一块儿看房是能够接受的。一种是真正的入住一晚,在这期间,不管是想入住的仍是想看房的都不能够。
锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁。
他们的加锁开销从大到小,并发能力也是从大到小。
InnoDB是基于索引来完成行锁
例: select * from tab_with_index where id = 1 for update;
for update 能够根据条件来完成行锁锁定,而且 ID 是有索引键的列,若是 ID不是索引键那么InnoDB将完成表锁,并发将无从谈起
1.Record lock:单个行记录上的锁
2.Gap lock:间隙锁,锁定一个范围,不包括记录自己
3.Next-key lock:record+gap 锁定一个范围,包含记录自己
Innodb对于行的查询使用next-key lock
Next-locking keying为了解决Phantom Problem幻读问题
当查询的索引含有惟一属性时,将next-key lock降级为record key
Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会致使幻读问题的产生
有两种方式显式关闭gap锁:(除了外键约束和惟一性检查外,其他状况仅使用record lock)
A. 将事务隔离级别设置为RC
B. 将参数innodb_locks_unsafe_for_binlog设置为1
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而致使恶性循环的现象。
常见的解决死锁的方法
一、若是不一样程序会并发存取多个表,尽可能约定以相同的顺序访问表,能够大大下降死锁机会。
二、在同一个事务中,尽量作到一次锁定所须要的全部资源,减小死锁产生几率;
三、对于很是容易产生死锁的业务部分,能够尝试使用升级锁定颗粒度,经过表级锁定来减小死锁产生的几率;
若是业务处理很差能够用分布式事务锁或者使用乐观锁
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操做。在查询完数据的时候就把事务锁起来,直到提交事务。
实现方式:使用数据库中的锁机制
乐观锁:假设不会发生并发冲突,只在提交操做时检查是否违反数据完整性。在修改数据的时候把事务锁起来,经过Version的方式来进行锁定。
实现方式:通常会使用版本号机制或CAS算法实现。
两种锁的使用场景
从上面对两种锁的介绍,咱们知道两种锁各有优缺点,不可认为一种好于另外一种,像乐观锁适用于写比较少的状况下(多读场景),即冲突真的不多发生的时候,这样能够省去了锁的开销,加大了系统的整个吞吐量。
但若是是多写的状况,通常会常常产生冲突,这就会致使上层应用会不断的进行Retry,这样反却是下降了性能,因此通常多写的场景下用悲观锁就比较合适。
感谢你们看到这里,文章有不足,欢迎你们指出;若是你以为写得不错,那就给我一个赞吧。