• Mysql的表级锁


    我们首先需要知道的一个大前提是:mysql的锁是由具体的存储引擎实现的。所以像Mysql的默认引擎MyISAM和第三方插件引擎 InnoDB的锁实现机制是有区别的。可根据不同的场景选用不同的锁定机制。
    Mysql有三种级别的锁定:表级锁定、页级锁定、行级锁定

    一、定义


    • 每次锁定的是一张表的锁机制就是表级别锁定(table-level)。它是MySQL各存储引擎中粒度最大的锁定机制。

    二、优缺点


    1. 优点

    • 实现逻辑简单,开销小。
    • 获取锁和释放锁的速度快。
    • 由于表级锁一次会将整个表锁定,所以能很好的避免死锁问题。

    2. 缺点

    • 由于锁粒度最大,因此出现争用被锁定资源的概率也会最高,致使并发度十分低下。

    三、支持存储引擎


    • 使用表级锁定的主要有MyISAM,MEMORY,CSV等一些非事务性存储引擎。

    四、表级锁类型


    MySQL的表级锁有两种类型:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。

    锁模式的兼容性:

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

    MyISAM表的读操作与写操作之间,以及写操作之间是串行的。当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。

    五、如何加表锁


    • 在执行查询语句(select)前,会自动给涉及的所有表加读锁
    • 在执行更新操作(update、delete、insert等)前,会自动给涉及的表加写锁。这个过程并不需要用户干预,因此不需要直接用lock table命令给MyISAM表显式加锁。

    显示加写锁:

    // 当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。
    // 其他线程的读、写操作都会等待,直到锁被释放为止。
    // test表将会被锁住,另一个线程执行select * from test where id = 3;将会一直等待,直到test表解锁
    LOCK TABLE test WRITE; 
    

    显示加读锁

    // test表将会被锁住,另一个线程执行select * from test where id = 3;不会等待
    // 执行UPDATE test set name='peter' WHERE id = 4;将会一直等侍,直到test表解锁
    LOCK table test READ;
    

    显示释放锁:

    UNLOCK TABLES;
    

    需要注意的是,在同一个SQL session里,如果已经获取了一个表的锁定,则对没有锁的表不能进行任何操作,否则会报错。

    // 锁定test表
    LOCK table test WRITE;
    

    // 操作锁定表没问题
    SELECT * from test where id = 4;

    // 操作没有锁的表会报错
    SELECT * from bas_farm where id =1356

    报错:[Err] 1100 - Table 'bas_farm' was not locked with LOCK TABLES。这是因为MyISAM希望一次获得sql语句所需要的全部锁。这也正是myisam表不会出现死锁的原因。

    当然,你也不必担心,MyISAM引擎的默认方式是会给同一个session里的所有表都加上锁的,不会麻烦你自己显示操作的。

    六、查看表级锁争用情况


    执行:show status like ‘table%’;

    mysql> show status like 'table%';
    +----------------------------+-----------+
    | Variable_name              | Value     |
    +----------------------------+-----------+
    | Table_locks_immediate      | 20708     |
    | Table_locks_waited         | 0         |
    +----------------------------+-----------+
    

    Table_locks_immediate:产生表级锁定的次数;
    Table_locks_waited:出现表级锁定争用而发生等待的次数;
    如果Table_locks_waited状态值比较高,那么说明系统中表级锁定争用现象比较严重,就需要进一步分析为什么会有较多的锁定资源争用了。

    七、优化表级锁定


    优化表级锁时的最大问题是:提高并发度
    ###1. 通过减少查询时间缩短锁定时间
    缩短锁定时间的总体原则是:让Query执行时间尽可能的短。

    • 尽量减少大的、复杂的Query,将复杂Query分拆成几个小的Query分步执行;
    • 尽可能的建立足够高效的索引,让数据检索更迅速;
    • 尽量让MyISAM存储引擎的表只存放必要的信息,控制字段类型;
    • 利用合适的机会优化MyISAM表数据文件。
    ###2. 设置可并发插入:concurrent_insert=2
    MyISAM的表锁虽是读写互相阻塞的,但依然能够实现并行操作。MyISAM存储引擎有一个控制是否打开Concurrent Insert(并发插入)功能的参数选项:concurrent_insert,取值范围为0,1,2。

    • concurrent_insert=0,不允许并发插入。
    • concurrent_insert=1,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个线程读表的同时,另一个线程从表尾插入记录。这是MySQL的默认设置;
    • concurrent_insert=2,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录;

    所以,我们可通过设置concurrent_insert=2,同时定期在系统空闲时段执行optimize table tableName语句来整理空间碎片,收回因删除记录而没有真正释放的空间,从而提高并发。optimize参考:mysql中OPTIMIZE TABLE的作用及使用
    ###3. 合理设置读写优先级
    MyISAM存储引擎默认是写优先级大于读优先级。即使是写请求后到,写锁也会插到读锁请求之前。

    但是,有时像修改文章点击数 操作是不那么重要的,我们希望的是读更快,此时我们可以这样:

    UPDATE  LOW_PRIORITY  article SET click_num=134 WHERE id = 823
    

    LOW_PRIORITY使得系统认为update操作优化级比读操作低,如果同时出现读操作和上面的更新操作,则优先执行读操作。

    MySQL提供了几个语句调节符,允许你修改它的调度策略

    • LOW_PRIORITY关键字应用于:DELETE、INSERT、LOAD DATA、REPLACE和UPDATE。
    • HIGH_PRIORITY关键字应用于:SELECT、INSERT语句。
    • delayed(延迟)关键字应用于:INSERT、REPLACE语句。

    如果你希望所有支持LOW_PRIORITY选项的语句都默认地按照低优先级来处理,那么可能使用**low-priority-updates**选项来启动服务器。然后可通过使用insert HIGH_PRIORITY table.....来把个别我们希望的INSERT语句提高到正常的写入优先级。

  • 相关阅读:
    MyISAM表锁的解决方案
    RSA数字证书管理
    Self Host WebApi服务传输层SSL加密(服务器端+客户端调用)
    WebApi服务Uri加密及验证的两种方式
    利用MVC的自定义过滤器FilterAttribute、IActionFilter、IExceptionFilter实现异常处理等功能
    html页面中meta的作用
    [转]REST简介
    [转]webApi 参数传递总结
    REST服务中的异常处理
    REST服务返回自定义的HttpResponseMessage
  • 原文地址:https://www.cnblogs.com/edda/p/13041986.html
Copyright © 2020-2023  润新知