锁
概念
锁是协调多个进程或县城并发访问的某一资源的一种机制,在数据库当中,除了传统的计算资源,(CPU,RAM,IO),数据也是一种共许多用户访问的共享资源,,如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素
分类
按照操分类
- 读锁(共享锁)
- 写锁(排它锁)
按照粒度分
- 表锁
- 行锁
- 页锁
表锁
偏向MYISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发量低
整张表只有一个人能使用
查看有没有被锁过show open tables
对表加读锁lock table (表名) read
对表加写锁lock table (表名) write
对表进行解锁unlock tables
性能影响
读锁(共享锁)
当前连接:可以查看自己,不能更新,不可用读取别的表
另一个链接:可以查看,当更新时就会进入阻塞,等待解锁后才能更新,可以读别的表
写锁(排它锁)
当前连接:可以查看自己,可以更新,不能读取别的表
另一个连接:进行查询和读取都会进入等待,可以读取别的表
分析
Myisam的读写锁调度室写优先,这也是myisam不适合作为主表的引擎,因为写锁后,其它线程不能做任何操作,大量更新会使用查询很难得到锁,从而造成永久阻塞
所以读数据比较多的时候用表锁
行锁
偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度最小,发生冲突的概率最低,并发度也最高
InnoDB与MyiSAM的最大不同1是支持事物,2是采用了行锁
MyISAM表锁 InnoDB行锁
问题并发处理带来的问题,更新丢失,脏读,不可重复读,幻读
mysql5.5之后,默认事物会自动提交
执行更新操作,自己可以查看到自己的更新内容,其他人看只有等commit之后才能看到更新内容
俩个人执行更新操作同一条记录的时候,连接1没有提交事时,连接2处于阻塞状态,当commit时,连接2才会继续执行(连接2更新也要commit)
更新的不是同一条记录的时候则不受影响
索引失效行锁会变成表锁
操作数据库的时候,没有使用索引去操作数据,那么行锁就会变成表锁
间隙锁
当使用范围查询的时候,会给满足组条件的内容进行加锁,比如:
update employee set name='123' where id>3 and id<7;
以上sql语句执行的时候,就会把3到7中间的内容进行加锁
可以在查询的时候在语句后面加上for update,就可以实现对某一行数据的锁死
查看行锁的状态show status like 'innodb_row_lock%';
悲观锁与乐观锁
悲观锁:
就是很悲观,它对于外界修改持保守的态度我,认为数据随时会修改,所以整个数据库处理中需要将数据加锁,悲观锁一半都是依靠关系型数据库提供的机制,事实上关系数据库中的行锁表锁,不论是读锁写锁,都是悲观锁.
乐观锁
顾明意思就是很乐观,每次自己操作数据的时候认为没有人回来修改它,所以不去加锁,但是在更新的时候回去判断在此期间数据有没有被修改,需要用户自己去实现,不会发生并发抢占资源只有在提交操作的的时候检查是否违反数据完整性
为什么要使用乐观锁
对于读取操作远多余写的时候,大多数都是读取,这时候一个更新加锁会阻塞所有读取,降低了吞吐量.最后还要释放锁,锁是需要一些开销的,我们只要想办法解决极少量的更新操作的同步问题
换句话说骂如果是读写比例差距不大的,或者没有系统响应不及时和吞吐量瓶颈的问题的问题的时候,那就不要去使用乐观锁,它增加了复杂度也带来了额外的风险
乐观锁实现方式
添加version字段做标记,在更新的时候,判断这个字段是否为取出的字段,如果是取出的字段,则值+1并进行更新操作
update table set name 'aaa' bersion=1+1 where id=1 and version=#{上一个取出来的版本号}
也可以使用时间戳的方式去更新,每次更新的时候,就把值更新为当前的时间戳
什么情况下会造成死锁
所谓死锁<DeadLock>: 是指两个或两个以上的进程在执行过程中,
因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.
此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程.
表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB.
死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
那么对应的解决死锁问题的关键就是:让不同的session加锁有次序