hello,word

一个小并发,引起的数据错误

1.昨天测试的时候遇到一个并发问题。用户2和用户6同一时间报名参加一个活动,数据除了写入报名表外,还写入了活动表,因此造成了并发问题,导致报名参加的总人数不正确。

再此之前也做过了一次改进,就是开启了事物。

理论上开启事物后,是不会引发写入数据错误问题的。因为事物本身对sql语句进行了加锁操作。但是昨天依然出现了问题,就有排查了一下,先看下日志

用户6增加了一个报名人数

图片

 用户2增加了一个报名人数

图片

这两个人报名后,总报名人数都更新为了17,那么说明他两人在读取报名人数的时候是同一时间,都是16个人。

这里就出现了一个问题,如果事物是枷锁的,那么此时用户2是读不到报名人数的。就只有两种情况了,第一种是事务不加锁,第二种情况是框架的事务没有起作用。

对于第二种我搜了下,没有相关文档,只能追源码。于是我反向搜了事务,发现是事务的读锁确实是不加的,只加了写锁。

图片

mysql的默认隔离级别为可重复读,不加读锁。这张图有个错误,就是可重复读时会出现幻读的,它没有解决这个问题

然后在看下程序

图片

 在此处使用了程序上的加法,因此并发时造成了数据问题。从上图的日志也可以看出问题所在。

这样理论上就诞生了两种解决方案

第一种:修改sql语句,不适用save的方法。使用update 字段+1的方式

第二种:在增加排他锁,在事务完成前,不允许读。

两种方法各有优缺点,此处我打算使用第一种方式,然后进行下测试

 

在将程序方法修改完后,又出现一个新的并发问题---幻读,

某用户第一次参加活动,连续点击两次。程序会先到数据库中读取报名记录,如果存在,报名人数+1,不存在,新增一条报名记录。

此时两个请求同时运行到select 报名记录,但是没有新增报名记录,两个请求程序判定都不存在记录,都会先后新增一条新的报名记录。

理论上本应该解决的幻读问题,事务并没有解决。

暂时现在前端做了误触处理,后续再看。

 

posted @ 2025-10-13 14:38  tying  阅读(11)  评论(0)    收藏  举报