zoukankan      html  css  js  c++  java
  • MyISAM表锁

    MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。

    • MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking)。
    • BDB 存储引擎采用的是页面锁(page-level locking),但也支持表级锁。
    • InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

    • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
    • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
    • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

    MySQL 的表级锁有两种模式:

    • 表共享读锁(Table Read Lock)
    • 表独占写锁(Table Write Lock)

    mysql表锁兼容性

    • 读操作,不会阻塞其他用户对同一表的读操作,但会阻塞对同一表的写操作
    • 写操作,会阻塞其他用户对同一表的写操作

    • 执行查询语句(SELECT)前,会自动给涉及的所有表加读锁。
    • 在执行更新操作 (UPDATEDELETEINSERT 等)前,会自动给涉及的表加写锁。

    这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

    • 在执行 LOCK TABLES 后,只能访问显式加锁的这些表,不能访问未加锁的表;

     

    •  在自动加锁的情况下也基本如此,MyISAM 总是一次获得 SQL 语句所需要的全部锁。这也正是 MyISAM 表不会出现死锁(Deadlock Free)的原因。
    • 当使用 LOCK TABLES 时,不仅需要一次锁定用到的所有表,而且,同一个表在 SQL 语句中出现多少次,就要通过与 SQL 语句中相同的别名锁定多少次,否则也会出错!

    比如如下SQL语句:

    select a.first_name,b.first_name, 
    
    from actor a,actor b 
    
    where a.first_name = b.first_name;

    该Sql语句中,actor表以别名的方式出现了两次,分别是a,b,这时如果要在该Sql执行之前加锁就要使用以下Sql:

    lock table actor as a read,actor as b read;
     

    如果用户想要显示的加锁可以使用以下命令:

    • 锁定表:LOCK TABLES tbl_name {READ | WRITE};
    • 解锁表:UNLOCK TABLES

    写阻塞读写例子

    session_1 session_2

    //获取写锁

    lock table film_text write;

     

     //对film_text进行读取,插入,更新操作

     select * from film_text where film_id=999G;

     insert into film_text(film_id,title) value (1001,'Test');

     update film_text set title='Test1' where film_id='1001';

     //对session_2进行操作

    //读操作等待

     select * from film_text where film_id=999G;

    //写操作等待

     insert into film_text(film_id,title) value (1001,'Test');

     //session_1 释放锁

    UNLOCK TABLES;

     
     

     //释放锁后,session_2再次进行读,写操作

    select * from film_text where film_id=999G;

    insert into film_text(film_id,title) value (1002,'Test');

    并发插入


    lock table film_text read local 

    在 local table 后面加 local 是为了在满足表并发插入的条件下,允许其他用户在表尾并发插入记录。

    MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为NEVER (or 0)AUTO(or 1)ALWAYS (or 2)

    • 当concurrent_insert设置为NEVER (or 0)时,不允许并发插入。
    • 当concurrent_insert设置为AUTO(or 1)时,如果MyISAM表中没有空洞(即表的中间没有被删除的 行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL 的默认设置。

    »»因删除表中记录而产生的中间空洞,需要定期使用optimize table table_name[,table_name]来收回空洞。««

    • 当concurrent_insert设置为ALWAYS (or 2)时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。

    MyISAM的锁调度


    前面讲过,MyISAM 存储引擎的读锁和写锁是互斥的,读写操作是串行的。那么,一个进程请求某个 MyISAM 表的读锁,同时另一个进程也请求同一表的写锁,MySQL 如何处理呢?

    答案是:写进程先获得锁

    不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求之前!这是因为 MySQL 认为写请求一般比读请求要重要。这也正是 MyISAM 表不太适合于有大量更新操作和查询操作应用的原因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。这种情况有时可能会变得非常糟糕!

    幸好我们可以通过 一些设置来调节 MyISAM 的调度行为。

    • 通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。
    • 通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。
    • 通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。

    MySQL也 供了一种折中的办法来调节读写冲突,即给系统参数max_write_lock_count 设置一个合适的值,当一个表的读锁达到这个值后,MySQL就暂时将写请求的优先级降低, 给读进程一定获得锁的机会。

    资料来源:《深入浅出Mysql--数据库开发,优化与管理维护》

  • 相关阅读:
    Python 类 元类 new之间的关系
    Scrapy Item类分析
    python中的可变参数和不可变参数
    简易python购物车
    关于Javascrip瀑布流深度解析
    python3.5 的str类型和bytes类型的转换
    php 扩展
    PHP开源网
    ElementUI中树形控件el-tree修改样式/添加title
    SVN 重命名文件夹
  • 原文地址:https://www.cnblogs.com/dsitn/p/7149354.html
Copyright © 2011-2022 走看看