10.MySQL 支持的锁

  1. MySQL 的所级别有三种
    行级锁、表级锁、页级锁。
    表锁:1)意向共享锁(IS锁) 2)意向排他锁(IX锁) 3)自增锁
    行锁:1)共享锁 2)排他锁
    共享锁:又称为读锁,简称 S 锁;共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
    排他锁:又称为写锁,简称 X 锁,排他锁就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务可以对数据就行读取和修改。
    意向锁:意向锁的作用是 InnoDB 为了让表锁和行锁共存的一种锁。当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个表的意向锁。(如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行或某些行的排他锁定,则申请一个意向排他锁。)
    意向锁是表锁:
    1)如果意向锁是行锁,则需要遍历每一行数据去确认;
    2)如果意向锁是表锁,则只需要判断一次即可知道没有数据行被锁定,提高性能;

    类型开销加锁速度死锁锁定粒度锁冲突概率
    行级锁最小最低
    表级锁不会最大最高
    页级锁适中适中适中适中
  2. MySQL InnoDB 既支持行级锁,也支持表级锁,默认行级锁。

  3. MySQL中的自增锁作用
    自增锁是一种特殊的表锁,如果表中存在自增字段,MySQL 便会自动维护一个自增锁,该锁会在 insert 结束后立即释放。

  4. MySQL 行锁
    MySQL 的行锁并不是直接锁记录,而是锁索引。如果一条 SQL 语句用到了主键索引,MySQL 会锁住主键索引,如果一条语句操作了非主键索引,MySQL 会先锁住非主键索引,再锁定主键索引。
    行锁实现的算法:
    1)Record Lock:单个记录上的锁
    锁总会锁住索引记录,锁住的是 key。如果 InnoDB 存储引擎表在建立的时候没有设置任何一个索引,那么这时 InnoDB 会使用隐式的主键进行锁定。
    2)Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
    锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别而配的;Gap Lock 在 InnoDB 的唯一作用就是防止其他事务的插入操作,以此防止幻读。
    3)Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身
    在 Next-Key Lock 算法下,InnoDB 对于行的查询都是采用这种锁定的算法。可以有效的防止幻读。
    当查询的索引含有唯一属性时,InnoDB 存储引擎会对 Next-Key Lock 进行优化,将其降级为 Record Lock,即仅锁住索引本身,而不是范围。
    当查询的索引为辅助索引时,默认使用 Next-Key Locking 技术进行加锁,锁定范围是前一个索引到后一个索引之间范围。

  5. MySQL 什么情况会发生死锁
    两个或两个以上事务在执行过程中因争抢锁资源而造成的互相等待就是死锁。
    产生死锁的四个必要条件:
    1)互斥条件
    一个资源每次只能被一个进程使用;
    2)请求与保持条件
    一个进程因请求资源而阻塞时,对以获得的资源保持不放;
    3)不剥夺条件
    进程已获得的资源,在使用完之前,不能强行剥夺;
    4)循环等待条件
    若干进程之间形成一种头尾相接的循环等待资源关系;
    死锁排查:
    1)查看当前事务中是否有锁信息
    select trx_id,trx_state,trx_started,trx_requested_lock_id,trx_weight from innodb_trx;
    2)查看锁信息(表锁or行锁,锁的那张表)
    select lock_id,lock_trx_id,lock_mode,lock_type,lock_table,lock_index from innodb_locks;
    3)查看锁在等待那些事务
    select * from innodb_lock_waits;
    死锁处理方式:
    1)超时等待(innodb_lock_wait_timeout = 50s)
    2)死锁检测,主动回滚一条事务,让其他事务继续执行(innodb_deadlock_detect = on)由于性能问题,一般推荐使用死锁检测来进行处理死锁。
    死锁检测:死锁检测的原理是构建一个以事务为顶点、锁为边的有向图,判断有向图是否存在环,存在即有死锁。
    回滚:检测到死锁之后,选择插入更新或者删除的行数最少的事务回滚,基于 INFORMATION_SCHEMA.INNODB_TRX 表中的 trx_weight 字段来判断。
    如何避免死锁:
    1)按顺序加锁
    如:Transaction 1:更新表A --> 更新表B;Transaction 2:更新表B --> 更新表A;这类问题要从程序上避免,所有的更新需要按照一定的顺序。
    2)添加合理的索引
    如果 SQL 不走索引将会为表的每一行记录添加上锁,死锁的概率大大增加。
    3)减少持有锁的时间
    保证没有长事务,尽量早提交事务,锁就越早释放。

  6. 乐观锁
    乐观锁就相当于 Java 的 CAS 算法,所以多条数据同时过来的时候,不用等待,可以立即进行返回。
    乐观锁可以采用版本号的方式,即当前版本号如果对应上了就可以写入数据,如果判断当前版本号不一致,那么久不会更新成功,比如:

    update table set column = value where version = ${version} and otherKey = ${otherKey}
    

    相对悲观锁,乐观锁更适合用于写少读多的情景,如果同时写比较多,循环次数比较多会造成数据库性能下降。

  7. 悲观锁
    悲观锁相当于 Java 的synchronized,reentrantLock 锁等,大量数据过来的时候,一条数据同时只有一个事务可以更新,其他数据需要等待,执行完成后下一条数据可以继续。
    悲观锁实现的机制一般是在执行更新语句的时候采用 for update 方式,比如:

    update table set column = 'value' for update;
    

    这种情况 where 条件一定要涉及到数据库对应的索引字段,这样才会是行级锁,否则会是表锁,这样执行速度会变慢。
    相对乐观锁,悲观锁更适用于写多读少的情景。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值