在事务相关话题中,已经提到事务隔离性依靠锁机制实现的。在本篇中围绕着InnoDB与MyISAM锁机制的不同展开,进而描述锁的实现方式,多种锁的概念,以及死锁产生的原因。

 
Mysql常用存储引擎的锁机制

MyISAM和MEMORY采用表级锁(table-level locking);

BDB采用页面锁(page-leve locking)或表级锁,默认为页面锁;

InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁;

各种锁特点


表级锁(table-level locking):开销小,加锁快;不会出现死锁;锁定粒度大,发生冲突的概率最高,并发度最低

行级锁(row-level locking):开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高

页面锁(page-level locking):开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般

 

锁的算法


InnoDB存储引擎有3种行所算法设计,分别是:

  • Record Lock:单个行记录上的锁
  • Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
  • Next-key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身

Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表建立的时候没有设置任何一个索引,这时InnodB存储引擎会使用隐式的主键来进行锁定,在Repeatable Read隔离级别下,Next-key Lock 算法是默认的行记录锁定算法。

阻塞、系统互斥量(mutex)和信号量(event)


因为不同锁之间兼容性关系,一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源。在InnoDB存储引擎的源代码中,用Mutex数据结构来实现锁。在访问资源前需要用mutex_enter函数进行申请,在资源访问或修改完毕后立即执行mutex_exit函数。当一个资源已被一个事务占有时,另一个事务执行mutex_enter函数会发生等待,这就是阻塞。阻塞并不是一件坏事,阻塞是为了保证事务可以并发并且正常运行。

在InnoDB引擎当中,封装了操作系统提供的基本mutex(互斥量)和event(信号量),在WINDOWS下的实现暂时不做记录,主要还是对支持POSIX系统来做介绍。在POSIX系统的实现是os_fast_mutex_t和os_event_t。os_fast_mutex_t相对简单,其实就是pthread_mutex。定义如下:

  1. typedef pthread_mutex os_fast_mutex_t;
而os_event_t相对复杂,它是通过os_fast_mutex_t和一个pthread_cond_t来实现的,定义如下:
  1. typedef struct os_event_struct
  2. {
  3. os_fast_mutex_t os_mutex;
  4. ibool is_set;
  5. pthread_cond_t cond_var;
  6. }os_event_t;
 

以下是os_event_t的两线程信号控制的例子流程:

 

对于系统的封装,最主要的就是os_event_t接口的封装,而在os_event_t的封装中,os_event_set、os_event_reset、os_event_wait这三 个方法是最关键的。

 

CAS原子操作


在InnoDB的mutex(互斥量)的实现中,除了引用系统的os_mutex_t以外,还使用了原子操作来进行封装一个高效的mutex实现。在系统支持原子操作的情况下,会采用自己封装的mutex来做互斥,如果不支持,就使用os_mutex_t。
因为我对于操作系统编程不熟,在此用Java的util.concurrent.atomic包举例,其封装了一些具有原子性操作的类,大量的利用了类似于mutex(互斥量)的操作。
CAS原子操作——Compare & Set,自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时才能进入临界区。
  1. /**
  2. * Atomically updates the current value with the results of
  3. * applying the given function, returning the previous value. The
  4. * function should be side-effect-free, since it may be re-applied
  5. * when attempted updates fail due to contention among threads.
  6. *
  7. * @param updateFunction a side-effect-free function
  8. * @return the previous value
  9. * @since 1.8
  10. */
  11. public final int getAndUpdate(IntUnaryOperator updateFunction) {
  12. int prev, next;
  13. do {
  14. prev = get();
  15. next = updateFunction.applyAsInt(prev);
  16. } while (!compareAndSet(prev, next));
  17. return prev;
  18. }
  19. /**
  20. * Atomically sets the value to the given updated value
  21. * if the current value {@code ==} the expected value.
  22. *
  23. * @param expect the expected value
  24. * @param update the new value
  25. * @return {@code true} if successful. False return indicates that
  26. * the actual value was not equal to the expected value.
  27. */
  28. public final boolean compareAndSet(int expect, int update) {
  29. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
  30. }
 

InnoDB存储引擎中的锁


InnoDB是一个多线程并发的引擎,内部的读写都是用多线程来实现的,所以InnoDB内部实现了一个比较高级的并发同步机制。InnoDB并没有直接使用系统提供的锁(latch)同步结构,而是对其进行自己的封装和实现优化,但是也兼容系统的锁。我们先看一段InnoDB内部的注释(MySQL-3.23):

Semaphore operations in operating systems are slow: Solaris on a 1993 Sparc takes 3 microseconds (us) for a lock-unlock pair and Windows NT on a 1995 Pentium takes 20 microseconds for a lock-unlock pair. Therefore, we have toimplement our own efficient spin lock mutex. Future operating systems mayprovide efficient spin locks, but we cannot count on that.

大概意思是说1995年的时候,一个Windows NT的 lock-unlock所需要耗费20us,即使是在Solaris 下也需要3us,这也就是他为什么要实现自定义latch的目的,在innodb中作者实现了系统latch的封装、自定义mutex和自定义 rw_lock。
InnoDB存储引擎实现了以下两种标准的行机锁:

共享锁(S Lock):允许事务读一行数据。
排他锁(X Lock):允许事务删除或者更新一行数据。
 
未完待续...
 
 
参考文献:

《MySQL技术内幕InnoDB存储引擎》

MySQL学习笔记-锁相关话题的更多相关文章

  1. MySQL学习笔记-事务相关话题

    事务机制 事务(Transaction)是数据库区别于文件系统的重要特性之一.事务会把数据库从一种一致状态转换为另一个种一致状态.在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都 ...

  2. MySQL学习笔记-数据库文件

    数据库文件 MySQL主要文件类型有如下几种 参数文件:my.cnf--MySQL实例启动的时候在哪里可以找到数据库文件,并且指定某些初始化参数,这些参数定义了某种内存结构的大小等设置,还介绍了参数类 ...

  3. MySQL学习笔记-数据库内存

    数据库内存 InnoDB存储引擎内存由以下几个部分组成:缓冲池(buffer pool).重做日志缓冲池(redo log buffer)以及额外的内存池(additional memory pool ...

  4. MySQL学习笔记-数据库后台线程

    数据库后台线程 默认情况下讲述的InnoDB存储引擎,以后不再重复声明.后台线程有7个--4个IO thread,1个master thread,1个锁监控线程,1个错误监控线程.IO thread的 ...

  5. MySQL学习笔记-cache 与 buffer

    Cache和Buffer是两个不同的概念,简单的说,Cache是加速"读",而 buffer是缓冲"写",前者解决读的问题,保存从磁盘上读出的数据,后者是解决写 ...

  6. MySQL学习笔记-大纲

    软件程序性能测试在之前<品味性能之道>系列中已经大量提到,讲解了很多测试方法.测试观念.测试思想等等.最近准备深入MySQL进行学习并总结.分别查阅<MySQL性能调优与架构设计&g ...

  7. MySQL学习笔记-MySQL体系结构总览

    MySQL体系结构总览 不管是用哪种数据库,了解数据库的体系结构都是极为重要的.MySQL体系结构主要由数据库和数据库实例构成. 数据库:物理操作系统文件或者其它文件的集合,在mysql中,数据库文件 ...

  8. 一千行MySQL学习笔记 (转)

    出处:  一千行MySQL学习笔记 /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权 ...

  9. mysql basic operation,mysql总结,对mysql经常使用语句的详细总结,MySQL学习笔记

    mysql> select * from wifi_data where dev_id like "0023-AABBCCCCBBAA" ; 1.显示数据库列表.show d ...

随机推荐

  1. Missing parentheses in call to 'print'

    这个消息的意思是你正在试图用python3.x来运行一个只用于python2.x版本的python脚本. print"Hello world" 上面的语法在python3中是错误的 ...

  2. 安装三代组装canu、smartdenovo、wtdbg及矫正软件Racon、Nanopolish的安装

    1)三代组装软件 ------------------------------------------------------------------canu--------------------- ...

  3. 无线LoRa智能远传水表

    1.1 主流程 无线远传智能预付费水表是基于瑞萨R7F0C002芯片开发的一款水表,该款水表包含了电子计数.远程充值.远程开关阀.费控.欠费提醒等功能. 水表通信采用LoRa无线模式,芯片采用SX12 ...

  4. msf客户端渗透(九):获取PHP服务器shell

    如果一个网页存在可以include外链的漏洞,我们可以利用这个漏洞include本机上的文件,从而获取web服务器的shell. 设置目标的IP 根据网页的路径设置参数 设置cookie 选择payl ...

  5. Pandas基本功能之算术运算、排序和排名

    算术运算和数据对齐 Series和DataFrame中行运算和列运算有种特征叫做广播 在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集.自动的数据对齐操作在不重叠的索引处引入了NA ...

  6. 在window下搭建Vue.Js开发环境(转)

    nodejs官网http://nodejs.cn/下载安装包,无特殊要求可本地傻瓜式安装,这里选择2017-5-2发布的 v6.10.3 cmd命令行: node -v //显示node版本 v6.1 ...

  7. 8个纯CSS3制作的动画应用及源码

    对于一个复杂的图形或者动画来说,之前我们的处理方式是图片叠加或者利用CSS+JavaScript的方法,然而随着CSS3标准的不断成熟,我们甚至完全可以利用CSS3来绘制一些图片和制作丰富的动画特效. ...

  8. 网站访问者UA检测及跳转

    /*!* UA检测及跳转*/;(function(){ var whatdevice = {}; var myUA = window.navigator.userAgent.toLowerCase() ...

  9. 今天设置apache二级域名ssl证书后出现问题

    用集成环境 phpwamp重启服务失败,但是重启电脑后apache就启动成功,也不知道哪里原因,待以后解决.

  10. c++ 读入优化、输出优化模板

    0. 在有些输入数据很多的变态题中,scanf会大大拖慢程序的时间,cin就更慢了,所以就出现了读入优化.其原理就是一个一个字符的读入,输出优化同理,主要使用getchar,putchar函数. 1. ...