mysql一个语句并发问题的思考

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kang389110772/article/details/79855798

mysql一个语句并发问题的思考

我们数据库的引擎是innodb

这是我们再做并发限制的时候,使用了一个语句insert into xx select .. from xx where yyyy这种形式的语句, 如果表里没有这条记录就添加。

在初步考虑的时候,这种情况下如果第一个事务还没提交,那么除非数据库的隔离级别是脏读,否则是读不到的。

但是在测试过程中,却发现只有第一个insert会返回1并且会block后续的insert。

不太理解。找些相关的官方文档看下

  1. INSERT sets an exclusive lock on the inserted row. This lock is an index-record lock, not a next-key lock (that is, there is no gap lock) and does not prevent other sessions from inserting into the gap before the inserted row.

    insert会设置一个排他锁在insert row。这是一个基于index(即便表上没有index,mysql也会默认创建一个唯一索引,see https://dev.mysql.com/doc/refman/5.7/en/innodb-index-types.html), 不是一个next-key锁,不会阻止其他会话插入

  2. INSERT INTO T SELECT … FROM S WHERE … sets an exclusive index record lock (without a gap lock) on each row inserted into T. If the transaction isolation level is READ COMMITTED, or innodb_locks_unsafe_for_binlog is enabled and the transaction isolation level is not SERIALIZABLE, InnoDB does the search on S as a consistent read (no locks). Otherwise, InnoDB sets shared next-key locks on rows from S. InnoDB has to set locks in the latter case: In roll-forward recovery from a backup, every SQL statement must be executed in exactly the same way it was done originally.

    这个语句会设置一个index record的排他锁。 如果事务是read committed或者启用了innodb_locks_unsafe_for_binlog并且事务不是SERIALIZABLE, innodb不会在S上设置锁。否则, InnoDB会在S上设置一个next-key锁。 InnoDB必须对后一种情况加锁,因为在恢复的时候,每个sql语句都必须和原来的顺序一样执行。

看了官方文档,我们总结了两点:

  1. 如果有primary 或者其他的unique的锁,那么insert会基于加上index record的排他锁
  2. 如果是insert..select… 这种形式下,insert会加一个排他锁,select 会加上一个共享的锁。

对于我们这里的语句,insert表和select表是一致的,而且通过不同的insert发现也是需要顺序的。
第一个语句执行的共享锁执行并且释放过后,才能进行由第二个语句获取排它锁和共享锁。

这是个人的理解,如果有任何不对的地方敬请指正。

猜你喜欢

转载自blog.csdn.net/kang389110772/article/details/79855798