• MySQL锁机制


    一、概况
    MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
    MySQL这3种锁的特性可大致归纳如下。
    ·表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
    ·行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
    ·页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
    从上述特点可见,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。
    二、MyISAM表锁
    MyISAM存储引擎只支持表锁,是现在用得最多的存储引擎。MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预。

    1、查询表级锁争用情况
    可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定争夺:
    mysql> show status like ‘table%’;
    +———————–+———-+
    | Variable_name | Value |
    +———————–+———-+
    | Table_locks_immediate | 76939364 |
    | Table_locks_waited | 305089 |
    +———————–+———-+
    2 rows in set (0.00 sec)Table_locks_waited的值比较高,说明存在着较严重的表级锁争用情况。

    2、MySQL表级锁的锁模式
    MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write
    Lock)。MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁。
    所以对MyISAM表进行操作,会有以下情况:
    a、对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
    b、对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
    3、并发插入
    原则上数据表有一个读锁时,其它进程无法对此表进行更新操作,但在一定条件下,MyISAM表也支持查询和插入操作的并发进行。
    MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。
    a、当concurrent_insert设置为0时,不允许并发插入。
    b、当concurrent_insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置。
    c、当concurrent_insert设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。
    4、MyISAM的锁调度
    由于MySQL认为写请求一般比读请求要重要,所以如果有读写请求同时进行的话,MYSQL将会优先执行写操作。这样MyISAM表在进行大量的更新操作时(特别是更新的字段中存在索引的情况下),会造成查询操作很难获得读锁,从而导致查询阻塞。
    我们可以通过一些设置来调节MyISAM的调度行为:
    a、通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。
    b、通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。
    c、通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。
    上面3种方法都是要么更新优先,要么查询优先的方法。这里要说明的就是,不要盲目的给mysql设置为读优先,因为一些需要长时间运行的查询操作,也会使写进程“饿死”。只有根据你的实际情况,来决定设置哪种操作优先。这些方法还是没有从根本上同时解决查询和更新的问题。
    在一个有大数据量高并发表的mysql里,我们还可采用另一种策略来进行优化,那就是通过mysql主从(读写)分离来实现负载均衡,这样可避免优先哪一种操作从而可能导致另一种操作的堵塞。下面将用一个篇幅来说明mysql的读写分离技术。
    三、InnoDB行锁

    InnoDB实现了以下两种类型的行锁。 

     共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。

     排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

    另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。

     意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

     意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

    上述锁模式的兼容情况具体如下表所示。

    InnoDB行锁模式兼容性列表

     

    请求锁模式

     

       是否兼容

     

    当前锁模式

    X

    IX

    S

    IS

    X

    冲突

    冲突

    冲突

    冲突

    IX

    冲突

    兼容

    冲突

    兼容

    S

    冲突

    冲突

    兼容

    兼容

    IS

    冲突

    兼容

    兼容

    兼容

    如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。

    意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁。

    ·共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。

    ·排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。

    用SELECT ... IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT... FOR UPDATE方式获得排他锁。 

  • 相关阅读:
    linux 下内存检查工具 valgrind 及 sanitizer 编译选项及静态检查工具
    jQuery中 inArray
    CLEAN crxMouse Gestures 插件被标记为不安全
    如何理解DMZ?
    如何完整备份浏览器数据(Chrome、Firefox)
    Windows 分屏工具
    JS监听H5返回
    华为账号安全性怎么样?
    IOS Safari keyup不生效如何解决?
    如何下载JD图片 不带logo图片?
  • 原文地址:https://www.cnblogs.com/hllnj2008/p/4064858.html
Copyright © 2020-2023  润新知