并发情况下临界值问题处理小记

上周双11,客户要跟风做个问卷答题领爱奇艺会员的活动。

客户那边和爱奇艺的合同是5000个会员,让我们做好并发控制,如果超过了我们要赔钱......

我们这边的流程是先查询数据库记录条数,如果小于5000,则调用爱奇艺的接口,

将返回数据与答题答案一起存在库中,如果大于5000,则只记录答题答案不调用

爱奇艺的接口。

由于公司基于数据库的查询有一套自己的方式,这里为了保证查询,调用爱奇艺,

新增数据都在一个事物内,这里采用了JDBC的方式连接数据库,手动设置提交或者回滚。

起初接到这个问题想通过单例模式来解决,后来因为客户要弄分布式服务就转换了思路,

采用“悲观锁”来解决问题,即通过对数据库上锁的方式来解决。

初步做法是

select * from xxx for update //通过for update锁住该表

//执行爱奇艺接口 insert xxxx //执行添加记录方法 commit() //提交事物

然后模拟并发,我们发现(A为先执行的程序,B为后执行的程序):

程序的执行顺序确实是按照我们预期的那样,待A commti之后 B才开始的查询,但是B 查询到的数据始终和 A查询到的条数相同。

这点让我很费解,起初以为是jdbc预查询导致的,后面用普通的查询语句一样还是这种情况,于是我做了如下模拟:

1):第一个用户进来调用for update语句查询

2)另外开个客户端也调用这个语句

3)此时显示正在执行,表示该表已经被第一个锁住,然后此时我在第一个锁住的客户端中添加了一条数据后提交

4)再看刚才正在执行的窗口

神奇的发现还是只有3条数据,没有刚才新增的数据。那么问题就是出在这里。

于是这时决定在调用查询之前先将表锁住,锁住后在去查询,调用接口,插入数据,提交,通过先锁表来保证真正的查询的数据为数据库的真实数据。

select * from xxx for update//通过for update锁住表

select count(*) from xxx 

//执行爱奇艺接口

insert xxxx //执行添加记录方法

commit() //提交事物

后解决。

原文地址:https://www.cnblogs.com/Onedayzk/p/7826797.html