[mysql 详解]myqsl 锁机制

mysql锁概念

锁是计算机协调多个进程或纯线程并发访问某一资源的机制。
保证数据并发访问的一致性、有效性

锁的运行

事务T在对某个数据对象(如表、记录等)操作之前,先向系统发出请求,对其加锁,加锁后事务T就对数据库对象有一定的控制,在事务T释放它的锁之前,其他事务不能更新此数据对象。

锁分类

按封锁类型

  • 排他锁(写锁、X锁)会阻塞其他事务读和写。
  • 共享锁(读锁、S锁)阻塞其他事务修改表数据。
  • 意向锁(innoDb特有,本身是表级锁,是为了解决表级锁和行级锁之间的冲突)
    (意向锁为了方便检测表级锁和行级锁之间的冲突,故在给一行记录加锁前,首先给该表加意向锁。也就是同时加意向锁和行级锁。)
  • 间隙锁(innoDb特有)

按封锁数据粒度

  • 行级锁(开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 表级锁(开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。事务中查询非索引字段会锁表
  • 页级锁(销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。事务中查询索引字段会锁该行数据

活锁、死锁

采用封锁的方法可以有效防止数据的不一致性,单封锁本身会引起麻烦,就是死锁和活锁。

活锁

  • 定义:如果事务T1封锁了数据对象R后,事务T2也请求封锁R,于是T2等待,接着T3也请求封锁R。当T1释放了加载R上的锁后,系统首先批准T3的请求,T2只能继续等待。接着T4也请求封锁R,T3释放R上的锁后,系统又批转了T4的请求。这样的一直循环下去,事务T2就只能永远等待了,这样情况叫活锁。
  • 解决方案:采用先来先服务的队列策略。队列式申请。

死锁

  • 定义:当两个事务分别锁定了两个单独的对象,这时每一个事务都要求在另一个事务锁定的对象上获得一个锁,因此每一个事务都必须等待另一个事务释放占有的锁。这就发生了死锁了。
  • 预防解决方案:一次封锁法、顺序封锁法
  • 诊断死锁的方法:超时法、事务等待图法。

myisam 引擎 锁机制

  • 读锁
  • 写锁

详解:
(一)MyISAM表的读操作,不会阻塞其他用户对同一个表的读请求,但会阻塞对同一个表的写请求。
(二)MyISAM表的写操作,会阻塞其他用户对同一个表的读和写操作。
(三)MyISAM表的读、写操作之间、以及写操作之间是串行的。
(四)当一个线程获得对一个表的写锁后,只有持有锁线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。
注意:
1. MySQL认为写请求一般比读请求重要。
2. MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

InnoDB引擎的锁机制

Innodb和myisam不同

  • 支持事务
  • 只是行级锁

    锁分类

  • 共享锁
  • 排他锁
  • 意向锁(其中意向锁分为意向共享锁和意向排他锁
    详解:
    (一)行锁是针对索引的
    (二)行锁真正的作用范围

两个引擎的死锁对比

MyISAM表锁是无死锁的,这是因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但是在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了InnoDB发生死锁是可能的。

for update 锁级别

  • 开启事务后,使用for update 会锁表,按照索引字段查询除外。
  • 开启事务后,按照索引索引字段会锁住该行数据,其他不受影响。
  • FOR UPDATE 是写锁,读操作不会锁住。
  • 不开启事务,FOR UPDATE 不会锁任何数据。

乐观锁、悲观锁

乐观锁:

  • 使用数据版本(Version)记录机制实现
  • 使用时间戳(timestamp)

悲观锁:

认为本次操作会发生并发冲突,所以一开始就对商品加上锁(SELECT … FOR UPDATE),然后就可以安心的做判断和更新,因为这时候不会有别人更新这条商品库存。

参考

MySQL FOR UPDATE 锁级别

面试必备之乐观锁与悲观锁

锁机制超详细解析(锁分类、事务并发、引擎并发控制)

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!