• 【Mysql】Mysql中的锁


    什么是锁

       锁是应对并发领域中常见的一种手段,比如在多线程编程中多个线程对同一个资源进行读写,这时候锁可以将并行化的访问变成串行化,来保证数据的安全。所以锁的主要作用是管理共享资源的并发时候的访问。Mysql中的锁是用于实现事务中的隔离性(Isolation)。

    Mysql中的锁

       Mysql锁的实现是由mysql各个存储引擎来实现的,每个存储引擎实现具体的锁机制。比如Innodb支持行锁,而Mysiam只支持表锁。

    Mysql锁的类型

          共享锁(也称读锁):简称S锁,多个线程可以在同一时间读取同一资源而不相互干扰。

          独占锁(也称写锁):简称X锁,出于数据完整性的考虑,独占所是排他的会阻塞其他的写锁和读锁,这样才能保证在同一时刻只有一个线程能写入数据,并防止其他线程读取正在写入的数据,这也是事务隔离性的体现。写锁和其他的锁是不兼容的。

      注意:

          Innode的锁都是行锁,兼容性是指同一行记录。

    锁的粒度

      锁的粒度是指锁的策略,指的是被加锁的最小资源单位,比如在行上加锁,那么加锁的最小单位指的就是行,这样的锁就称之为行级锁。如果锁的资源是数据页,那么久称为页级别锁,同理如果锁的最小单位是表,那么就是表级锁。为了能提高并发性,锁定资源尽肯能的小,最理想的方式就是只需要对要修改的数据进行精确的锁定。

         mysql提供两种锁的粒度,一种是表级锁(table-level),是mysql最基本的锁策略,开销小(并发性底),表锁在加锁时会锁定整张表,一个用户在写数据前要获得表锁去阻塞其他用户对表的操作,只有没有写锁时其他读取的用户才能取得读锁。另一种是行级锁(row-level),行级锁可以最大程度支持并发,不过开销比较大,而且是存储引擎实现。

      根据锁的粒度锁可分为:

        1. 行级锁
          开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

        2. 页级锁
          开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

        3. 表级锁
          开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

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

      表级锁和行级锁对比:

    • 表级锁: Mysql中锁定 粒度最大 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
    • 行级锁: Mysql中锁定 粒度最小 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。

             页级锁: MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。页级进行了折衷,一次锁定相邻的一组记录。BDB支持页级锁。开销和加锁时间界于表锁和行锁之间,会出现死锁。锁定粒度界于表锁和行锁之间,并发度一般。

    锁模式

    • 共享锁(S):又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
    • 排他锁(X):又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

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

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

    意向锁仅仅用于表锁和行锁的共存使用。如果我们的操作仅仅涉及行锁,那么意向锁不会对我们的操作产生任何影响。在任一操作给表A的一行记录加锁前,首先要给该表加意向锁,如果获得了意向锁,然后才会加行锁,并在加行锁时判断是否冲突。如果现在有一个操作要获得表A的表锁,由于意向锁的存在,表锁获取会失败(如果没有意向锁的存在,加表锁之前可能要遍历整个聚簇索引,判断是否有行锁存在,如果没有行锁才能加表锁)。   

    同理,如果某一操作已经获得了表A的表锁,那么另一操作获得行锁之前,首先会检查是否可以获得意向锁,并在获得意向锁失败后,等待表锁操作的完成。也就是说:1.意向锁是表级锁,但是却表示事务正在读或写某一行记录;2.意向锁之间不会冲突, 因为意向锁仅仅代表要对某行记录进行操作,在加行锁时,会判断是否冲突;3.意向锁是InnoDB自动加的,不需用户干预。

    Innodb存储引擎中的锁

      1. 共享/排他锁(Shared and Exclusive Locks)

      2. 意向锁(intention Locks)

      3. 记录锁(Record Locks)

        只锁记录。表现为仅仅锁着单独的一行记录。

      4. 间隙锁(Gap Locks)

        只锁间隙。表现为锁住一个区间(注意这里的区间都是开区间,也就是不包括边界值)。

      5. 临键锁(Next-key Locks)

        同时锁住记录和间隙。从实现的角度为record lock+gap lock,而且两种锁有可能只成功一个,所以next-key是半开半闭区间,且是下界开,上界闭。一张表中的next-key锁包括:(负无穷大,最小的第一条记录],(记录之间],(最大的一条记录,正无穷大)。

      6. 插入意向锁(insert Intention Locks)

        插入操作时使用的锁。在代码中,插入意图锁实际上是Gap锁上加了一个LOCK_INSERT_INTENTION的标记。也就是说insert语句会对插入的行加一个X记录锁,但是在插入这个行的过程之前,会设置一个Insert intention的Gap锁,叫做Insert intention锁。

      7. 自增锁(Auto-inc Locks)

          针对自增列自增长的一个特殊的表级别锁。可以使用如下语句查看 :

        SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';

    查看Innodb锁情况

    #有加锁的情况这里可以查看到
    show full processlist;
    
    #可以查看innodb引擎相关锁的状态,是否有死锁等
    show engine innodb status;
    
    #查看当前锁的信息
    select * from information_schema.INNODB_LOCKS;
    
    #查看锁等待信息
    select * from information_schema.INNODB_LOCKS_WAITS;

    一致性非锁定读与一致性锁定读

      一致性非锁定读(consistent nonlocking read):指的是如果一条记录被加了X锁,其他事务还能读取这条记录。

      一致性锁定读(consistent locking read):指的是一个事务可以通过SELECT语句给某条记录加X锁或者X锁。

    #会对查询的行及相关联的索引记录加X锁,其他事务请求的S锁或X锁都会被阻塞。
    SELECT...FOR UPDATE #对读取的行添加S锁,其他事物可以对这些行添加S锁,若添加X锁,则会被阻塞。 SELECT...LOCK IN SHARE MODE
  • 相关阅读:
    文章目录
    平滑的加权轮询
    ESG
    JDK
    集合
    数组
    多线程(下)
    多线程
    Java常用类
    jdk5.0新增线程创建方式
  • 原文地址:https://www.cnblogs.com/songgj/p/9129284.html
Copyright © 2020-2023  润新知