什么是锁?
锁(lock)在多人处理同一个数据的时候,保证每次只有一个人可以操作。MySQL提供了页锁(全局锁)、行锁、表锁。其中innodb采用的是行锁和表锁,myisam只支持表锁。
什么是死锁
是指二个或者二个以上的进程在执行时候,因为争夺资源造成相互等待的现象,进程一直处于等待中,无法得到释放,这种状态就叫做死锁,
死锁出现的案列
批量入库,存在则更新,不存在则插入,insert into tab(xx,xx) on duplicate key update xx=‘xx’。
如何处理死锁?
1:通过innodblockwait_timeout来设置超时时间,一直等待直到超时
2:发起死锁检测,发现死锁之后,主动回滚死锁中的事务,不需要其他事务继续
如何避免死锁?
- 为了在单个innodb表上执行多个并发写入操作时避免死锁,可以在事务开始时,通过为预期要修改行,使用select …for update语句来获取必要的锁,即使这些行的更改语句是在之后才执行的
- 在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应先申请共享锁,更新时在申请排他锁。因为这时候当用户在申请排他锁时,其他事务可能又已经获得了相同记录的共享锁,
- 如果事务需要修改或锁定多个表,则应在每个事务中以相同的顺序使用加锁语句。在应用中,如果不同的程序会并发获取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会。
- 通过 select …lock in share mode获取行的读锁后,如果当前事务在需要对该记录进行更新操作,则很有可能造成死锁;
- 改变事务隔离级别
innodb默认是如何对待死锁的?
innodb默认是使用设置死锁时间来让死锁超时的策略,默认innodblockwait_timeout设置的时长是50s
如何开启死锁检测?
设置innodbdeadlockdetect设置为on可以主动检测死锁,在innodb中这个值默认就是on开启的状态
什么是全局锁?它的应用场景有哪些?
全局锁就是对整个数据库实例加锁,它的典型使用场景就是做全库逻辑备份,这个命令可以使用整个库处于只读状态,使用该命令之后,数据更新语句,数据定义语句,更新类事务的提交语句等操作都会被阻塞。
使用全局锁会导致的问题?
如果在主库备份,在备份期间不能更新,业务停止,所以更新业务会处于等待状态
如果在从库备份,在备份期间不能执行主库同步的binlog,导致主从延迟
如何处理逻辑备份时,整个数据库不能插入的情况?
如果使用全局锁进行逻辑备份都会让整个库成为只读状态,解决办法需要使用MySQLdump时,使用参数-single-transaction就会在导入数据之前启动一个事务来保证数据的一致性,并且这个过程是支持数据更细操作的。
什么是共享锁?
共享锁是读取操作创建的锁。其他用户可以并发读取数据,但是任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。当如果事务对读锁进行修改操作,很可能会操作死锁。
什么是排他锁?
排他锁又称写锁
事务对某一行加上排他锁,只能这个事务对其进行读写操作,在事务结束以前,其他事务不能对其进行加任何锁,其他进程可以读取,但是不能进行写操作,需要等待释放以后。排他锁是悲观锁的一种实现。
事务1对数据对象A加上排他锁,事务1可以读写A,其他事务就不能在对A进行任何加锁操作,直到事务1释放A上的锁,这保证其他事务在事务1释放A上的锁之前不能在读取和修改A,排他锁会阻塞所有的排他锁和共享锁。
悲观锁和乐观锁的区别?
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据都会block直到它拿到锁。因此,悲观锁需要耗时比较的多,跟乐观锁比较,悲观锁是有数据库自己实现的,用的时候我们直接调用数据的相关语句就可以
悲观锁涉及到的另另两个锁,他们是共享锁和排他锁,共享锁和排他锁时悲观锁的不同的实现,属于悲观锁的范畴。
乐观锁是用数据版本记录机制实现,这是乐观锁最常用的方式,所谓的数据版本,为数据增加一个版本号的字段,一般是通过为数据表增加一个数据类型的version字段实现,当读取数据时,将把二十年字段的值一同读取出来,数据每次更新都需要对version值加一,在我们提交更新的时候,判断数据表对应记录的当前版本信息与第一次取出来的version值进行对比,如果数据库的表当前版本号鱼取出来的version值相等,则给与更新否则认为过期数据不给与更新。
乐观锁有什么优点和缺点?
乐观锁虽然叫锁其实在使用的时候是没有加锁,所以执行性能高。缺点:会产生ABA的问题,ABA问题指的是有一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到他的值还是为A值,会误认为没有被修改做为正常的执行修改操作,实际上这段时间他的值可能被修改为其他值,之后又被修改为A值,
innodb存储引擎有几种算法?
1.record lock—单个行记录上的锁
2.gap lock — 间隙锁,锁定一个氛围,不包括记录本身
3.next-key lock–锁定一个范围,包含记录本身
innodb如何实现行锁?
行锁是MySQL中粒度最小的一种锁,innodb的行锁有共享锁和排他锁两种,共享锁允许事务读一行记录,不允许任何线程对行记录进行修改操作,排他锁允许当前事务删除或者更新一行记录,其他线程不能操作该记录。
优化锁方面的意见?
- 使用较低的隔离级别
- 设计索引,尽量使用索引去访问数据,加锁更加精确,从而减少锁冲突
- 选择合理的事务大小,
- 给记录显示加锁时,最好一次性请求足够级别的锁。列如,修改数据的话,最好申请排他锁,而不是先申请共享锁,修改时在申请排他锁,这样会导致死锁
- 不同的程序访问一组表的时候,应尽量约定一个相同的顺序访问各表,对于一个表而言,尽可能的固定顺序的获取表中的行。这样大大的减少死锁的机会。
- 尽量使用相等条件访问数据,这样可以避免间隙锁对并发插入的影响
- 不要申请超过实际需要的锁级别
- 数据查询的时候不是必要,不要使用加锁。MySQL的MVCC可以实现事务中的查询不用加锁,优化事务性能:MVCC只在committed read(读提交)和 repeatable read (可重复读)两种隔离级别
- 对于特定的事务,可以使用表锁来提高处理速度活着减少死锁的可能。