MySQL的单表模拟锁的几个场景

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

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

初始化数据

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

建表语句:

创建表测试(

id int not null,

name int,

主键(id),

唯一键(名称)

)engine = innodb;

事务隔离级别:

mysql>显示'%isolation%'等变量;

+ --------------- + ----------------- +

| Variable_name | 价值|

+ --------------- + ----------------- +

| tx_isolation | REPEATABLE-READ |

+ --------------- + ----------------- +

1排(0.00秒)

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

模拟死锁


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

会话1:

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

的MySQL>开始;

mysql>插入测试值(2017,827);

查询OK,1行受影响(0.01秒)


会话2;

mysql>插入测试值(2016,827);

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


会话1:

mysql>插入测试值(2018,826);

查询正常,1行受影响(0.00秒)


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


会话2:

mysql>插入测试值(2016,827);

ERROR 1213(40001):尝试锁定时发现死锁; 尝试重新启动事务

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

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

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


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

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

的MySQL>提交;

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

会话1:

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


mysql> select * from test;

+ ------ + ------ +

| id | 名字|

+ ------ + ------ +

| 2018年| 826 |

| 2017年| 827 |

+ ------ + ------ +

2行(0.00秒)

我们显式声明一个事务。

mysql>开始;

查询正常,0行受影响(0.02秒)

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

mysql>插入测试值(2019,825);

查询正常,1行受影响(0.00秒)

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

mysql>开始;

mysql>插入测试值(2015,830);


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

mysql> select * from test;

+ ------ + ------ +

| id | 名字|

+ ------ + ------ +

| 2018年| 826 |

| 2017年| 827 |

+ ------ + ------ +

2行(0.00秒)


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

mysql> rollback;

查询OK,0行受影响(0.01秒)

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

mysql> select * from test;

+ ------ + ------ +

| id | 名字|

+ ------ + ------ +

| 2018年| 826 |

| 2017年| 827 |

+ ------ + ------ +

2行(0.00秒)


间隙锁测试

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

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


会话1:

mysql>开始;

查询正常,0行受影响(0.00秒)

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

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

+ ------ +

| id |

+ ------ +

| 2018年|

| 2017年|

+ ------ +

2行(0.00秒)


会话2:

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

mysql>开始;

查询正常,0行受影响(0.00秒)

mysql>插入测试值(2016,829);

ERROR 1205(HY000):超出锁定等待超时; 尝试重新启动事务

直到事务超时才作罢。


原文:http //blog.itpub.net/23718752/viewspace-2144203/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL业务测试数据是指在测试MySQL数据库时使用的数据,这些数据可以模拟真实的业务场景,以便测试数据库的性能和可靠性。以下是几种创建MySQL业务测试数据的方法: 1.手动插入数据:可以手动编写SQL语句,将数据插入到MySQL数据库中。这种方法适用于数据量较小的情况。 2.使用工具生成数据:可以使用一些工具,如DataFactory、Mockaroo等,生成大量的测试数据。这些工具可以生成各种类型的数据,如数字、字符串、日期等。 3.使用自定义函数:可以通过MySQL新建一个自定义函数,这个函数通过项目的业务去决定新建哪些数据,并且下次需要实现时直接使用该函数,可以多次模拟场景。 4.使用基准测试工具:可以使用一些基准测试工具,如SysBench、HammerDB等,来测试MySQL数据库的性能和可靠性。这些工具可以生成大量的测试数据,并模拟真实的业务场景。 ```mysql -- 示例:使用工具生成数据 -- 安装DataFactory pip install datafactory -- 导入DataFactory from datafactory import DataFactory -- 生成测试数据 df = DataFactory() data = df.get_data('name', 'email', 'phone', size=1000) -- 将数据插入到MySQL数据库中 import mysql.connector mydb = mysql.connector.connect( host="localhost", user="yourusername", password="yourpassword", database="mydatabase" ) mycursor = mydb.cursor() sql = "INSERT INTO customers (name, email, phone) VALUES (%s, %s, %s)" val = [] for d in data: val.append((d['name'], d['email'], d['phone'])) mycursor.executemany(sql, val) mydb.commit() print(mycursor.rowcount, "记录插入成功。") -- 相关问题-- 1. 如何使用基准测试工具测试MySQL数据库的性能? 2. 如何使用Python连接MySQL数据库? 3. 如何使用Python生成随机数据?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值