MySQL单表模拟锁的有哪些场景

39次阅读
没有评论

共计 2543 个字符,预计需要花费 7 分钟才能阅读完成。

这篇文章主要介绍 MySQL 单表模拟锁的有哪些场景,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

  在 MySQL 中对于并发,锁问题总是会有很多值得讨论的地方,但是通常来说,要模拟这些锁或者一些锁的问题需要花点功夫,比如创建多个表,创建大量的数据,然后像调试钟表的秒针一样,让问题刚好复现在哪个时间点上。如果换一个角度,单表来模拟这类而是可以吗,其实是可行的。

    今天简单通过单表的测试模拟死锁,事务中的隐式提交(其实可以理解是个 bug), 间隙锁。

初始化数据

首先的准备工作就是初始化数据,我们创建一个表 test, 事务隔离级别为默认的 RR。

建表语句:

create table test(

id int not null ,

name int ,

primary key(id),

unique key(name)

) engine=innodb;

事务隔离级别:

mysql show variables like %isolation%

+—————+—————–+

| Variable_name | Value           |

+—————+—————–+

| tx_isolation  | REPEATABLE-READ |

+—————+—————–+

1 row in set (0.00 sec)

除此之外就是打开两个窗口,我们简称为会话 1,会话 2.

模拟死锁

我们开始先模拟一下死锁问题。

会话 1:

我们开启一个事务,插入一行记录,数据就选做今天的日期吧。

mysql begin;

mysql insert into test values(2017,827);

Query OK, 1 row affected (0.01 sec)

会话 2;

mysql insert into test values(2016,827);

这个时候会话 2 会阻塞,这个时候有一种特殊的情况,那就是阻塞超时,如果超时,会自动停止。

会话 1:

mysql insert into test values(2018,826);

Query OK, 1 row affected (0.00 sec)

可见会话 1 中的 DML 操作依旧是可以的。

会话 2:

mysql insert into test values(2016,827);

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

如果看会话 2 的情况,就会发现产生了死锁。

如果要尝试事务隔离级别 RC, 其实表现的效果是一样的。

仔细看看这个操作的过程就会发现,还是蛮“奇怪”的,数据之间彼此没有直接的依赖关联,怎么会产生死锁,这个里面有银式锁升级,还有间隙锁的一些东西,留给大家思考吧。

模拟意料之外的事务自动提交

为了基于上面的测试数据,让两条数据成功插入,我们在会话 2 中结束事务。

mysql commit;

然后开始做意料之外的事务自动提交测试,这一次我们在同一个会话中测试即可。问题的背景是如果我们显式声明事务,在同一会话中做了 DML 操作,没有提交,如果再开启一个事务,之前的事务会自动提交。

会话 1:

这是基于场景 1 的测试之后的数据情况。

mysql select *from test;

+——+——+

| id   | name |

+——+——+

| 2018 |  826 |

| 2017 |  827 |

+——+——+

2 rows in set (0.00 sec)

我们显式声明一个事务。

mysql begin;

Query OK, 0 rows affected (0.02 sec)

然后插入一条记录,重新给一个日期。

mysql insert into test values(2019,825);

Query OK, 1 row affected (0.00 sec)

这个时候没有提交,我们在当前会话中重新再开启一个事务。

mysql begin;

mysql insert into test values(2015,830);

这个时候如果在会话 2 中查看,其实会发现,事务已经帮你提交了。

mysql select *from test;

+——+——+

| id   | name |

+——+——+

| 2018 |  826 |

| 2017 |  827 |

+——+——+

2 rows in set (0.00 sec)

在会话 1 我们继续回滚事务,会发现于事无补。

mysql rollback;

Query OK, 0 rows affected (0.01 sec)

这个时候数据已经自动提交了一部分。

mysql select *from test;

+——+——+

| id   | name |

+——+——+

| 2018 |  826 |

| 2017 |  827 |

+——+——+

2 rows in set (0.00 sec)

间隙锁测试

上面的测试场景其实还是多多少少都有些关联,其中第一个场景和间隙锁也有关系,我就简单用单表模拟一下间隙锁。

首先还是保证事务隔离级别是 RR, 因为间隙锁是 RR 隔离级别特供,RC 中就没有间隙锁这样的定制,在并发场景中还是有不小的影响。我们来看看效果。

会话 1:

mysql begin;

Query OK, 0 rows affected (0.00 sec)

指定数据范围,然后显示声明。

mysql select id from test where id 2019 lock in share mode;

+——+

| id   |

+——+

| 2018 |

| 2017 |

+——+

2 rows in set (0.00 sec)

会话 2:

会话 2 中也开启一个事务,插入一条记录。结果就被阻塞了。

mysql begin;

Query OK, 0 rows affected (0.00 sec)

mysql insert into test values(2016,829);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

直到事务超时才作罢。

以上是“MySQL 单表模拟锁的有哪些场景”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注丸趣 TV 行业资讯频道!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计2543字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)