zoukankan      html  css  js  c++  java
  • MySQL--MyISAM之锁机制

    一、概述
    MySQL有三种锁的级别:页级、表级、行级。
    MyISAM存储引擎采用的是表级锁(table-level locking);
    MySQL这3种锁的特性可大致归纳如下:
    表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
    行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
    页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
     
    二、MyISAM表锁
    MyISAM存储引擎只支持表锁,是现在用得最多的存储引擎。
    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/(Table_locks_immediate+Table_locks_waited)
      这个比例值越大说明表级锁争用的情况越严重。
      例:比例值=0.01说明100次进程里就有一次是需要等待锁的进程;
     
     
    2、MySQL表级锁的锁模式
    MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table WriteLock)。MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁。所以对MyISAM表进行操作,会有以下情况:

    读锁:当某一进程对某张表进行读操作时(select),其他线程也可以读,但是不能写。简单的理解就是,我读的时候你不能写。

    写锁:当某一进程对某种表某张表的写时(insert,update,,delete),其他线程不能写也不能读。可以理解为,我写的时候,你不能读,也不能写。

    因此MyISAM的读操作和写操作,以及写操作之间是串行的!MyISAM在执行读写操作的时候会自动给表加相应的锁(也就是说不用显示的使用lock table命令),MyISAM总是一次获得SQL语句所需要的全部锁,这也是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表中有没有空洞,都允许在表尾并发插入记录。
     
    例子:
    当前进程:
    1)mysql> lock table first_test read local;--加入local选项是说明,在表满足并发插入的前提下,允许在末尾插入数据。当前进程不能进行插入和更新操作
       Query OK, 0 rows affected (0.00 sec)
     
    2)mysql> insert into first_test(age) values(15);
       ERROR 1099 (HY000): Table 'first_test' was locked
       with a READ lock and can't be updated
     
    3)mysql> update first_test set age=200 where id =1;
       ERROR 1099 (HY000): Table 'first_test' was locked
       with a READ lock and can't be updated
     
    其他进程:
    1)mysql> insert into first_test(age) values(15);--其他进程可以进行插入、查询和更新操作,但是更新操作要等待。。。
       Query OK, 1 row affected (0.00 sec)
     
    2)mysql> update first_test set age=200 where id =2;
       等待.....
     
    3)mysql> select * from first_test;
    +----+----+
    | id |age |
    +----+---+
    | 1 | 100|
    | 2 | 11 |
    | 3 | 12 |
    | 4 | 13 |
    | 5 | 14 |
    | 6 | 14 |
    +---+-- -+
    6 rows in set (0.00 sec)
     
    释放锁以后皆大欢喜
    mysql> unlock table;
    Query OK, 0 rows affected (0.00 sec)
     
    4、MyISAM的锁调度

    在MyISAM中当一个进程请求某张表的读锁,而另一个进程同时也请求写锁,Mysql会先让后者获得写锁。即使读请求比写请求先到达锁等待队列,写锁也会插入到读锁之前。因为Mysql总是认为写请求一般比读请求重要,这也就是MyISAM不太适合有大量的读写操作的应用的原因,因为大量的写请求会让查询操作很难获取到读锁,有可能永远阻塞。

    可以通过一些设置来调节MyISAM的调度行为:
    a、通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。
    b、通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。
    c、通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。
        上面3种方法都是要么更新优先,要么查询优先的方法。这里要说明的就是,不要盲目的给mysql设置为读优先,因为一些需要长时间运行的查询操作,也会使写进程“饿死”。只有根据实际情况,来决定设置哪种操作优先。
  • 相关阅读:
    根据group by、count case when 分组分类统计
    Cron表达式
    SQL分页查询 — 不同页面的查询结果有重复数据
    Dockerfile文件语法
    redis获取系统当前时间
    mybatis oracle批量插入数据
    Mysql函数->TRIM(去掉首尾空格、任意字符)
    Oracle函数->TRIM(去掉首尾空格、首尾字符)
    使用redis-list类型 限制用户1分钟内访问次数为100次
    一文了解mysql基础架构
  • 原文地址:https://www.cnblogs.com/ouruola863/p/8482242.html
Copyright © 2011-2022 走看看