zoukankan      html  css  js  c++  java
  • MySQL 有关锁的简单介绍

    一、Latch & Lock 

    在数据库中 Latch & Lock 都可以被称为锁,但两者有着截然不同的意义。

    Latch 一般被称为闩锁(轻量级的锁),锁定的时间很短,若持续的时间长,则应用的性能会非常差。

    在 InnoDB 中 Latch 锁又可以分为 mutex (互斥量) 和 rwlock (读写锁)。其主要目的是用来保证并发线程操作临界资源的正确性,并且没有死锁检测机制。

    ## Latch 是一个非常透明的东西,一般除了非常底层的数据库人员很难看懂

    ## show engine innodb mutex;

    Lock 的对象是事务,用来锁定的数据库中的对象,如表,页,行。一般 Lock 的对象仅在事务 commit 或rollback 后进行释放(不同事务隔离级别释放的时间可能不同)。Lock 与 Latch 不同的是 Lock 有死锁检测机制的。

    二、InnoDB 存储引擎中的锁

    一、InnoDB 存储引擎中的锁:

    S 行级共享锁:允许事务读一行数据;lock in share mode。

    X 行级排他锁 :  允许事务更新或删除一行数据;增删改产生排它锁,还有一个比较特殊 select ... for update。

    IS : 意向锁

    IX : 意向排他锁

    AI : 自增锁,AI 自增锁 ,自增锁是用来做自增的并发控制的。

    二、锁之间的兼容性

    锁兼容(Lock Compatible): 如果事务T1 获得行 r 的共享锁,那么另外的事务 T2 可以立即获得行 r 的共享锁,因为读取并没有改变行 r 的数据。

    锁不兼容: 若有其他的事务 T3 想获得行 r 的排他锁,则必须等待事务 T1、T2 释放行 r 上的共享锁。

                  表 1-1 排它锁和共享锁的兼容性

    从表1-1 可以看出 ,X锁与任何的锁都不兼容,而 S 锁仅和 S 锁兼容。S 锁 和 X 锁都是行锁 ,兼容是指对同一记录(row)锁的兼容情况。

    意向锁: 用来实现多粒度级别的锁的。

      揭示下一层级请求的锁类型。

      IS : 事务想要获得一张表中某几行的共享锁

      IX : 事务想要获得一张表中某几行的排它锁

    InnoDB 中意向锁都是表锁(简单的这样理解下)

    数据库总共有表锁,页锁,记录锁,但是在 MySQL 中只有表锁跟记录锁,意向锁都是加在表上的。

    意向锁之间都是兼容的,用来揭示下一层级的锁。

                  表 1-2 InnoDB 存储引擎中锁的兼容性

     三、查看锁对象内容

    使用 show engine innodb status 

    (root@localhost) [(none)]> pager less
    PAGER set to 'less'
    (root@localhost) [(none)]> 
    (root@localhost) [(none)]> show engine innodb status G
    TRANSACTIONS
    ------------
     

     如果想查看比较详细的锁的信息,可通过开启 innodb_status_output_locks  

    (root@localhost) [test]> set global innodb_status_output_locks=1;
    Query OK, 0 rows affected (0.00 sec)
    
    (root@localhost) [test]> show variables like '%innodb_status_output%';
    +----------------------------+-------+
    | Variable_name              | Value |
    +----------------------------+-------+
    | innodb_status_output       | OFF   |
    | innodb_status_output_locks | ON    |
    +----------------------------+-------+
    2 rows in set (0.00 sec)

    如下是开启 innodb_status_output ,show engine innodb status 输出的详细信息:

    找到 TRANSACTIONS , heap_no 2,3,4 表示的是插入的顺序,其中包含两个隐藏列, len 6 是指针列,len 7 是什么列来着忘了

    在 show engine innodb status 中的 thread_id 对应的是 show processlist 中 processlist_id 。

    这样看有点麻烦,可以借助 information_schema 中的几张表,innodb_trx,innodb_locks,innodb_lock_waits

    在 5.7 版本中有一张 innodb_lock_waits 

    (root@localhost) [sys]> select * from innodb_lock_waitsG
    *************************** 1. row ***************************
                    wait_started: 2019-02-28 16:26:18
                        wait_age: 00:00:18
                   wait_age_secs: 18
                    locked_table: `test`.`lock_1`
                    locked_index: PRIMARY
                     locked_type: RECORD
                  waiting_trx_id: 260217
             waiting_trx_started: 2019-02-28 16:26:18
                 waiting_trx_age: 00:00:18
         waiting_trx_rows_locked: 1
       waiting_trx_rows_modified: 0
                     waiting_pid: 18
                   waiting_query: update  lock_1 set b=6 where a=4
                 waiting_lock_id: 260217:217:3:3
               waiting_lock_mode: X
                 blocking_trx_id: 260213
                    blocking_pid: 19
                  blocking_query: NULL
                blocking_lock_id: 260213:217:3:3
              blocking_lock_mode: X
            blocking_trx_started: 2019-02-28 16:11:46
                blocking_trx_age: 00:14:50
        blocking_trx_rows_locked: 1
      blocking_trx_rows_modified: 0
         sql_kill_blocking_query: KILL QUERY 19
    sql_kill_blocking_connection: KILL 19
    1 row in set, 3 warnings (0.00 sec)
     # kill query :表示杀掉查询,
     # kill 表示这个连接也杀掉

     四、AI 自增锁

    MySQL 的自增存在一个回溯问题,简单说 MySQL 的自增是不持久化的。当数据库被异常重启 可以通过 select max(auto_inc_col)from t for update;
    重新获得表的自增起始id 值,这个可能会造成 id 冲突。

    自增锁在提交完成之后就已经被释放了。所以自增锁持有的时间是SQL的执行时间。假如你插入的是一个大事务的话就会出现阻塞了。

    而x,ix 等是需要commit 之后才能释放的。

     

    设置 innodb_autoinc_lock_mode=2 // 每一条记录加锁释放,这个提高了并发能力,但是可能出现一条语句中的数据不连续了。

  • 相关阅读:
    ubuntu基本配置学习(1)
    UITabBarController使用详解
    Could not find a storyboard named 'Main' in bundle NSBundle </Users/tianxiao/
    检查更新功能
    SDWebImage手动清除缓存的方法
    错误记录1
    如何获取path路径
    iOS如何获得本地Documents下的文件夹名称或文件名称
    重头系统的学习,不会咱就学!2014.6.18
    错误1
  • 原文地址:https://www.cnblogs.com/Camiluo/p/10444582.html
Copyright © 2011-2022 走看看