精华内容
下载资源
问答
  • Mysql共享锁, 排他锁和意向锁的简单总结共享锁(Share Lock)排他锁(Exclusive Lock)意向锁(Intent Lock)InnoDB... 共享锁可以重复加, 但与排他锁(X)是有冲突的, 也就是只读 使用语法: SELECT … LOCK IN SHARE MODE;...

    共享锁(Share Lock)

    1. 共享锁又称读锁, 缩写(S)锁. 共享锁可以重复加, 但与排他锁(X)是有冲突的, 也就是只读
    2. 使用语法: SELECT … LOCK IN SHARE MODE;

    排他锁(Exclusive Lock)

    1. 排他锁又称写锁, 缩写(X)锁. 排他锁加了, 不允许加其它任何锁
    2. 使用语法: SELECT … FOR UPDATE;

    意向锁(Intent Lock)

    • 意向锁是表级锁, 在事务中, 用户申请加行锁时, 数据库会默认先申请意向锁, 也就是数据库自动处理意向锁的.

    InnoDB的两种表意向锁

    1. 意向共享锁(Intent Share Lock), 缩写(IS)锁
    2. 意向排他锁(Intent Exclusive Lock), 缩写(IX)锁

    加锁过程说明

    1. 未加意向锁时: 某 A用户事务中加了行锁, 之后某 B用户申请加表锁, 此时 B用户的请求在数据库内处理冲突的步骤, 首先判断是否已被其它事务加了表锁, 再判断表中是否有个行已被加了行锁, 遍历整张表
    2. 有意向锁时: A用户事务中申请意向共享锁, 成功后再申请行锁, 之后 B用户申请加表锁, 此时 B用户的请求在数据库内处理冲突的步骤, 首先判断是否已被其它事务加了表锁, 然后会发现已有意向共享锁锁住了某个行, B进入阻塞, 直到 A释放指定行锁
    • 能看出未加意向锁时, 可能会有整表遍历, 导致加锁的性能损失会很严重

    各锁之间兼容详情表

    - S X IS IX
    S 兼容 冲突 兼容 冲突
    X 冲突 冲突 冲突 冲突
    IS 兼容 冲突 兼容 兼容
    IX 冲突 冲突 兼容 兼容

    如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

    展开全文
  • 一、共享锁、排它锁 InnoDB实现了如下两种标准的行级锁: 共享锁(S Lock):允许事务读一行数据 排它锁(X Lock):允许事务删除或更新一行数据 ... 下图显示了共享锁和排它锁的兼容性: 二、意向锁 此外,

    一、共享锁、排它锁

    • InnoDB实现了如下两种标准的行级锁
      • 共享锁(S Lock)允许事务读一行数据
      • 排它锁(X Lock)允许事务删除或更新一行数据

    锁之间的兼容性

    • 如果一个事务占用行r的共享锁那么其他事务都可以立即获取这个共享锁,但是如果有的事务像获取排它锁就需要等待,等待对行r的共享锁全部被释放才可以

    • 如果你一个事务占用行r的排它锁那么其他事务不论是占用改行的共享锁还是排他锁都需等待

    • 下图显示了共享锁和排它锁的兼容性:

    二、意向锁

    • 此外,InnoDB存储引擎支持多粒度锁定这种锁定允许事务在行级上的锁和表级上的锁同时存在为了支持在不同力度上进行加锁操作,InnoDB存储引擎支持一种额外的锁定方式,称之为意向锁(Intention Lock)
    • InnoDB支持意向锁设计比较简单,其意向锁即为表级别的锁。设计目的主要是为了在一个事务中揭示下一行将被请求的锁类型
    • 其支持两种意向锁:
      • 意向共享锁(IS Lock)事务想要获得一张表中某几行的共享锁
      • 意向排它锁(IX Lock)事务想要获得一张表中某几行的排他锁

    原理图解

    • 意向锁是将锁定的对象分为多个层次意向锁意味着事务希望在更细粒度上进行加锁。如下图所示
    • 将上锁的对象看成一棵树,那么对最下层的对象上锁(也就是对最细粒度的对象进行上锁),那么首先需要对粗粒度的对象上锁
    • 例如:需要对页上的记录进行行上的X锁,那么分别需要对数据库、表、页上意向锁,最后对记录上X锁。若其中任何一个部分导致等待,那么该操作需要等待粗粒度锁的完成。
    • 例如:已经有事务对表进行了S表锁,此时想在对记录上加X锁,此时需要对表加IX锁,但是发现表已经加了S锁,因此需要等待表锁操作的完成

    三、查看锁的信息

    查看锁请求信息

    • 可以通过下面的信息查看当前锁请求的信息:
    show engine innodb status\G
    •  可以看到SQL语句“select * from t where a<4 lock in share mode”在等待
    • RECORD LOCKS space id 30 page no 3 n bits 72 index 'PRIMARY' of table 'test'.'t' trx id 48B89BD lock_mode X locks rec but not gap表示锁住的资源
    • locks rec but not gap代表锁住的是一个索引,不是一个范围

    • 在InnoDB 1.0版本之前,用户只能通过命令SHOW FULL PROCESSLIST、SHOW ENGINE INNODB STATUS查看当前数据库中锁的请求,然后再判断事务锁的情况
    • 从InnoDB 1.0版本开始,在information_schema数据库下添加表innodb_trx、innodb_locks、innodb_lock_waits。通过这三张表可以更简单地监控当前事务并分析可能存在的锁问题

    innodb_trx表

    • 该表由8个字段组成:

    • 接下来看一个具体的例子:
      • 通过trx_state列观察到trx_id为730FEE的事务当前正在运行,而trx_id为7311F4的事务目前处于“LOCK WAIT”状态,且运行的SQL语句在trx_query中显示

    • innodb_trx表只是显示当前运行的InnoDB事务并不能直接判断锁的一些情况

    innodb_locks表

    • 如果需要查看锁则还需要访问表innodb_locks表。该表的字段如下:

    • 接下来看一个具体的例子
      • rx_id为730FEE的事务向表parent加了一个X的行锁,trx_id为7311F4的事务向表parent加了一个S的行锁
      • 两个事物都锁定了同一个行记录,且行记录的主键值为1,因此lock_data都是1,申请相同的资源,因此会等待

    • lock_data值的注意事项lock_data这个值并非是“可信”的值。例如当用户运行一个范围查找时,lock_data可能只返回第一行的主键值。与此同时,如果当前资源被锁住了,若锁住的页因为InnoDB存储引擎缓冲池的容量,导致该页从缓冲池中被刷出,则查看innodb_locks表时该值同样会显示为NULL,即InnoDB不会从磁盘进行再一次的查找

    innodb_lock_wait表

    • 通过表innodb_locks查看了每张表上锁的情况后,用户可以来判断由此引发的等待情况了。当事务较小时,用户可以直观的看出,但是如果事务量非常大,其中锁和等待就非常多,此时不容易判断。但是通过表innnodb_lock_waits就可以反应出当前事务的等待
    • 该表有4个字段组成,含义如下

    • 接下来看一个具体的例子:
      • 例子中可以看到哪个事务阻塞了另一个事务

    • 当然,这里只给出了事务和锁的ID。如果想要观察更为详细的信息,可以进行下面的联合查询

     

     

     

     

    展开全文
  • 的类型和兼容

    千次阅读 热门讨论 2016-09-11 21:02:37
    当我们使用单击版的系统时,根本不需要考虑并发量,但现在我们很多的系统都会有大量用户,我们就不得不面对并发,当出现并发...共享锁主要用于读写数据操作,它是非读占的,允许其他事务同时读取其锁定的资源,但不允

       当我们使用单击版的系统时,根本不需要考虑并发量,但现在我们很多的系统都会有大量用户,我们就不得不面对并发,当出现并发访问时,我们自然会想到加锁,而数据库会自动管理锁,当进行查询和修改数据库时,自动为其加上锁。接下来我们先来看一下有哪几种锁!


    一、共享锁

       共享:正如这个词的中文意思一样,大家可以可以共享资源。共享锁主要用于读写数据操作,它是非读占的,允许其他事务同时读取其锁定的资源,但不允许修改。

       特点:

         加锁条件:当一个事务执行查询Select语句时,数据库会自动为其加上一把共享锁,来锁定被查询的数据

         解锁条件:默认情况下,当数据库被读取后,数据库立即解除共享锁。

         与其他所的兼容性:数据上还可以防止共享锁和更新锁

         并发性能:具有良好的并发性能,当多个事务读取相同的数据时,每个事务会得到一把共享锁,故可以

                同时读锁定的数据。


    二、独占锁

       人如其名,非常霸道,只能自己来使用,不允许其他事务读取和修改。独占锁,也叫排他锁,适用于修改数据 的地方,我自己来修改,改完后其他事务才可以操作。

       特点:

          加锁条件:当一个事务执行insert、update、delete语句时,数据库会自动对SQL语句操作的数据资源

                使用独占锁。如果数据资源上已有其他锁,将不能添加独占锁。

          解锁条件:当事务结束,独占锁被解除。

          与其他所兼容性:不能兼容其他锁

          并发性能:并发性能差,只允许一个事务访问访问锁定的资源。其他事务需要访问相同资源时,必须等

                待前一个事务结束,解除了独占锁,其他事务才有机会访问该数据。


    三、更新锁

       更新是初始化阶段用来锁定可能要被修改的资源,这样可以避免死锁现象。 

       例如:update语句

        update T_user set user_name ="zss" where id =1;

       使用更新锁,更新数据的操作分为两步:

       (1)获得一个更新锁,读取T_user表中id为1的记录

       (2)将更新锁升级为独占锁,更新数据库表中的数据

       特点:

          加锁条件:当一个事务执行update语句时,数据库为事务分配一个更新锁。

          解锁条件:当数据读取完毕,执行更新操作时,将更新锁升级为独占锁。

          与其他锁兼容性:更新锁和共享锁兼容,但一个资源最多放置一个更新锁

          并发性能:允许多个事务同时读锁定的资源,但不允许其他事务修改它。


    四、总结

       我们操作数据库,从数据库角度来看,就是这三种锁,我们利用锁就是用来解决高并发访问下数据不一致的额问题。这是从数据库角度来看我们将锁分为三种,我们看看从开发人员的角度来看,锁又分为哪几种呢?期待我的更新吧!

               

    展开全文
  • 1.锁的目的是什么?innodb中利用mvcc(多版本并发控制),可以在不加锁的情况下提高并发访问下系统的吞吐量,但有些场景下...按兼容性分类,分为S 共享锁和X 排他锁。S锁之间是兼容的,但X锁不与其他锁兼容。按粒度...

    1.锁的目的是什么?

    innodb中利用mvcc(多版本并发控制),可以在不加锁的情况下提高并发访问下系统的吞吐量,但有些场景下并发访问必须要在锁的保护下进行,比如并发的更新。

    2.锁的分类

    一般锁是指lock,innodb中还有不常用的一种轻量级锁latch,latch中不存在死锁检测机制,适合加锁时间较短的场景。

    按兼容性分类,分为S 共享锁和X 排他锁。S锁之间是兼容的,但X锁不与其他锁兼容。

    按粒度分类,分为表级锁、页锁(innodb中好像没有?)、行级锁。innodb支持多粒度锁,它允许行级锁与表级锁共存。

    3.表锁

    mysql的MyISAM使用的是表锁,而innodb有表锁和行锁。

    innodb表级锁包括自增锁、意向锁。

    自增锁 AUTO-INC Locks,用于AUTO_INCREMENT的自增主键。在Innodb存储引擎的内存结构中,对每个含有自增长值的表都有一个自增长计数器。当对表进行插入操作时,会依据自增长计数器的计数值加一赋予自增长列.为了提升插入的性能,锁不是事务完成后才释放,而是完成自增长值插入的sql语句后立即释放。

    意向锁 Intention Locks,表示事务有意向对表中的某些行加锁,分为IS 意向共享锁和IX 意向排他锁。IS表示有意向对表中的某些行加共享锁,IX表示有意向对表中的某些行加排他锁。意向锁是由引擎自己维护的,用户无法手动操作,在给数据行加共享/排他锁之前,Innodb会先给对应的表加意向锁。

    意向锁之间是相互兼容的,IX与IX之间也相互兼容。另外,意向锁也不会与行级的共享/排他锁互斥。

    意向锁的作用是什么? 意向锁会与表级的共享/排他锁互斥,这里的表级锁指普通的表级锁。例如,事务A执行 SELECT * FROM USERS WHERE ID=9 FOR UPDATE, 此时USERS表有两把锁,USERS表上的IX锁和ID=9的数据行上的排他锁。在事务A未commit的情况下,事务B执行LOCK TABLES USERS READ,此时事务B检测到事务A持有表的IX锁,就可以得知A必然持有该表中某些行的排他锁,因此B对USERS的加锁请求就会被阻塞,就无需检测表中每一行的数据是否存在排他锁。

    4.行级锁

    分为Record Lock,Gap Lock和Next-Key Lock。这里锁都是针对索引,通过索引来实现行锁,而不是通过锁住记录。数据库操作使用主键索引时,会锁住主键索引;使用非主键索引时,会先锁住非主键索引,再锁住主键索引,这样就有可能导致死锁(A先锁住非主键索引再锁住主键索引,而B先锁住主键索引)。

    Record Lock,是单个行记录上的锁。

    Gap Lock,间隙锁,锁住一个范围,但是不包含记录本身。例如事务A执行SELECT * FROM USERS WHERE ID>5 AND ID<8 FOR UPDATE,此时就会锁住(5,8)的区间,事务B尝试插入ID=6的操作就会被阻塞。间隙锁之间互不冲突,它的唯一作用是防止其他事务的插入,因此加间隙S锁和间隙X锁没有区别。RR隔离级别下特有。

    Next-Key Lock,Record Lock+Gap Lock,锁住记录本身,并且锁定一个范围。它的主要目的是,保证Repeatable Read(RR)的事务隔离级别下不出现Phantom Problem幻读问题。innodb默认的事务隔离级别是Repeatable Read,在RR中innodb行锁默认使用Next-key Lock,只有当查询的索引时唯一索引时,innodb会对next-key lock进行优化,将其降级为Record Lock,即仅锁住单条索引本身而不是范围。当查询的索引为辅助索引时,innodb会使用next-key lock加锁。

    5.MVCC

    多版本并发控制,不加锁的情况下支持并发查询提高并发度。在Read Committed和Repeatable Read隔离级别下有不同的表现。Innodb中每一行有三个隐藏列,DATA_TRX_ID表示最近修改该行数据的事务id,DATA_ROLL_PTR表示指向该行undolog段段指针,DELETED_BIT标记该列是否被删除,mvcc就是通过这三个隐藏列实现。

    Read Committed隔离级别下,每次查询得到的是当前已经提交的数据。Repeatable Read级别下,查询得到的是事务开始前的数据。

    怎么实现的? 核心内容:事务版本号,表的隐藏列,undo log和read view。通过读取undo log的历史版本数据,来实现不同事务拥有自己独立的快照数据版本。

    主要过程:获得事务版本号;获取一个read view;查询到数据,与read view事务版本号进行批评;不符合read view规则的从undolog里获取历史版本数据;返回符合规则的数据。

    Read View, 每个sql执行前,都会得到一个read_view,主要保存了当前数据库系统中正处于活跃(没有commit)的事务ID号。不同隔离级别下,根据不同的条件匹配read view。RC隔离级别下,同一个事务里的每一次查询都会获得一个新的read view副本,这样既可能造成同一个事务里前后读取数据可能不一致问题(重复读)。RR级别下,一个事务里只会获取一次read view副本,从而保证每次查询的数据都是不一致的。Read Uncommitted级别下,事务不会获取read view副本。

    事务版本号, 事务开始前都会从数据库获取一个自增长的事务ID,可以根据事务ID判断事务的执行先后顺序。

    5.phantom problem幻读问题

    解决:mvcc+next-key lock?为什么mvcc不够?

    什么是phantom problem?

    RR隔离级别下,全部使用快照读不会存在幻读问题,但是快照读和当前读混用时会存在幻读问题,因此需要间隙锁机制。

    实例如下:

    a. 事务A执行SELECT * FROM T WHERE ID>3 返回ID=3和4两条记录;

    b. 事务B插入了一条ID=5的数据并commit;

    c.事务A执行SELECT * FROM T WHERE ID>3 得到3、4两条记录;

    d. 事务A执行UPDATE T SET NAME='..' WHERE ID>3 更新三条记录;

    e. 事务A再次执行SELECT * FROM T WHERE ID>3 得到3、4、5三条记录。

    a和c两步均为快照读,因此都只能读取到两条记录,且不对数据加锁。b中插入ID=5的数据,在d中是可见的,因为UPDATE中使用当前读读取最新commit的数据,如果不使用当前读会有数据覆盖问题。因为事务A在d中对ID=5的数据进行了更新,因此A中快照进行了更新,e中可以查询到5这条记录。

    事务A中快照读和当前读混用,导致了幻读问题。如果都使用当前读即a中使用SELECT FOR UPDATE,则b中插入操作会阻塞,A中的update和select都始终只会影响两条记录。当前读使用了间隙锁,因此会阻塞b中操作。

    快照读和当前读 快照读是读取数据时,不读取最新版本数据,而是基于历史版本读取的一个快照信息(innodb基于undo log历史版本),快照读可以使用普通的SELECT读取数据不用对表数据进行加锁。当前读是读取最新的数据,需要对数据加锁。update、delete、insert、select ... lock in share mode和select ... for update 为当前读。RC隔离级别下,只加record lock,而在RR下加Record Lock。

    6.参考

    《MySQL内幕:Innodb存储引擎》大名鼎鼎,但是很多东西讲的不清楚,遗憾。

    意向锁

    各种锁,幻读

    展开全文
  • 主要内容如下:共享锁和排他锁(Shared and Exclusive Locks)InnoDB实现标准的行级锁定,其中有两种类型的锁: 共享(S)锁和排他(X)锁。共享(S)锁允许持有锁,读取行的事务。独占(X)锁允许持有锁,更新或删除行的事务...
  • 重点介绍了MySQL 中MyISAM 表级锁和InnoDB 行级锁的实现特点,并讨论了两种存储引擎经常遇到的锁问题和解决办法。对于MyISAM 的表,主要讨论了以下几点:共享读锁(S)之间是兼容的,但共享读锁(S)与排他写锁(X)之间,...
  • 预备知识 ​ mysql5.5以上版本中默认使用的存储引擎是基于InnoDB,...共享锁(S):共享锁也称为读锁,共享锁和共享锁之间是兼容的,但和排他锁不兼容。什么意思呢?假设事务A加了一个共享锁,那么事务B是可以申请共享
  • 共享锁(S Lock),允许事务读一行数据 排他锁(X Lock),允许事务删除或更新一行数据 兼容性: S与S可以兼容 X不与任何锁兼容 InnoDB支持多粒度锁定,也就是允许行级表级的锁同时存在。实现方式为通过意向锁...
  • 锁的类型在数据库中,对数据的操作其实只有两种,即读和写,所以可用共享锁和互斥锁实现,即共享锁间之间是兼容的,而互斥锁间不兼容。共享锁(读锁):允许事务读互斥锁(写锁):允许事务删除或者更新一行数据共享...
  • InnoDB_总结

    2020-02-14 22:38:13
    加了共享锁的资源不可以被修改;但可以被查询(也是会在资源上再加共享锁) 2. 数据修改会对资源添加排他锁 加了排他锁的资源只能被持有这个排他锁的事务读取修改,其他事务读取或者修改这个资源会被阻塞 ...
  • 锁的类型在数据库中,对数据的操作其实只有两种,即读和写,所以可用共享锁和互斥锁实现,即共享锁间之间是兼容的,而互斥锁间不兼容。共享锁(读锁):允许事务读互斥锁(写锁):允许事务删除或者更新一行数据共享...
  • DB2的lock

    2020-03-17 13:35:08
    X锁与S锁和X锁都不可以兼容。 举例: 一条记录加了共享锁(S),那么其他事务也可以对该条记录加共享锁(S); 但是不能加排他锁,需要等到该共享锁释放之后再加排他锁。 一条记录加了排他锁(S), 那么其他...
  • 共享锁,排他锁,意向共享锁,意向排他锁,插入意向锁 意向锁(插入意向锁不包括)之间互相兼容可以说意向锁就是为了提高锁判断的效率的。两个事务都对同一个表加意向排他锁,也就是两个事务都是修改数据,那么...
  • 关于数据库的分享

    2020-04-14 14:54:23
    锁的介绍: ... 共享锁和排它锁是innoDB实现的标准行级锁:也就是s锁和x锁。 排它锁(x锁):可以让持有锁的事务更新或者删除一行。 共享锁(s锁):可以让持有锁的事务读取一行。 举个例子: ...
  • 深入了解MYSQL

    2020-10-12 23:04:20
    在数据库中,对数据的操作其实只有两种,即读和写,所以可用共享锁和互斥锁实现,即共享锁间之间是兼容的,而互斥锁间不兼容。 共享锁(读锁):允许事务读 互斥锁(写锁):允许事务删除或者更新一行数据 共享锁代表了...
  • 数据库的机制

    2017-10-11 17:04:29
    1.数据库规定对于同一资源不能同时共存共享锁和排他锁。 2.共享锁兼容,两个共享锁是可以存在同一资源上的,表明共享锁不阻止 其它session同时读资源, 但阻止其它session进行update操作。 3.更新锁(为了解决死锁...
  • 线程安全和锁优化

    2017-02-15 15:46:03
    绝对线程安全、 相对线程安全、 线程兼容和线程对立。 1.不可变  不可变(Immutable)的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要再采取任何的线程安全保障措施。  Java语言中,...
  • 数据库

    2012-10-07 22:34:00
    锁只有共享锁和排他锁两种。锁的兼容性: SXS 10X 00 事务的隔离级别:Read Uncommitted数据读取时不需要锁定Read Committed数据读取时需要共享锁定Repeatable Read数据读取时需要排他锁Serializable事务必须等同于...
  • MySQL读这篇就够

    2020-11-21 07:26:31
    S-共享锁:又叫读锁,其它事务可以继续加共享锁,但是不能继续加排他锁 X-排他锁:又叫写锁,一旦加了写锁之后,其它事务不能加锁了 兼容性:是指事务A获得一个某行某种锁之后,事务B同样的在这个行上尝试获取某种...
  • 共享锁(Share),简称S锁,又称读锁 X锁和S锁都是表锁,有以下两个规定: 一个事务对数据对象 A 加了 X 锁,就可以对 A 进行读取和更新。加锁期间其它事务不能对 A 加任何锁 一个事务对数据对象 A 加了 S 锁,可以...
  • 最近在看mysql技术内幕这本书,分享一些阅读笔记 innoDB存储引擎主要实现了以下两种标准的行级锁: 1、共享锁:允许事务读一...以下列出了排他锁X和共享锁S的兼容情况 我们可以发现X锁与任何的锁都不兼容,而S锁和S锁
  • 数据库的基本了解

    2020-12-01 23:01:53
    表锁 就是在数据表层面加锁。分别是有读锁和写锁。...共享锁(shared lock):允许事务读行,使用共享锁后,其他事务可以获取相同数据集的共享锁,但是不能获得排他锁。手动加锁方式 select * from t
  • 关注:架构师学习路线,每日更新互联网最新技术文章与你不断前行,实战资料,笔试面试目录InnoDB 行锁锁排查可以用的视图数据字典InnoDB 行锁兼容性InnoDB行锁之共享锁共享锁:查看InnoDB锁InnoDB行锁实现机制对...
  • Sql Server 中的概念

    2019-03-13 12:41:00
    锁的类型:(1) 共享锁:共享锁用于所有的只读数据操作.(2) 修改锁:修改锁在修改操作的初始化阶段用来锁定可能要被修改的资源,这样可以避免使用共享锁造成的死锁现象(3) 独占锁:独占锁是为修改数据而保留的。...
  • 在数据库中,对数据的操作其实只有两种,即读和写,所以可用共享锁和互斥锁实现,即共享锁间之间是兼容的,而互斥锁间不兼容。 共享锁(读锁):允许事务读互斥锁(写锁):允许事务删除或者更新一行数据 共享锁代表...
  • 因为X锁和S锁既可以是行级锁也可以是表级锁, 假设在没有使用意向锁的时候,那么情景是这样的, 事物T想给数据库表tableA加表级X锁,因为X锁和X锁不兼容, 先要检查数据库表tableA目前有没有被加X锁(行级X锁或者表...
  • 一、概述 锁是数据库系统区别于文件系统的一个重要特性,锁机制可以用来管理对并发资源的访问,因此有了锁之后极大地提升了读写数据。InnoDB存储引擎同时支持行锁和表锁。...S锁只和S锁兼容,X锁和...

空空如也

空空如也

1 2 3 4 5 6
收藏数 120
精华内容 48
关键字:

共享锁和共享锁可以兼容