您的位置:首页 > 编程语言 > Java开发

for update...

2016-01-05 17:34 405 查看
一.业务背景

目前,我有下面一个业务场景。多个用户访问页面,我会从数据库里面分配一个数据码给每个用户。这个数据码可以使用的前提是它的状态是0.我的sql是这样写的:

select * from tb_status where status=0 order by id asc limit 1;


我会找到当前状态可用,id最小的这条数据。业务逻辑是获取这条数据后,这条记录的status变成1,不可用。

二.正常场景

现在,我们来看一下这个业务的简易流程图。



当访问间隔时间很大,看上去没有任务问题,数据正常!

三.高并发场景

试想下下面这种情况:



当用户1和用户2访问间隔时间很短,或者说用户1还没有更新完status,用户2恰好执行了这条sql,那么用户1和用户2就获取到了同样的code,这显然不是我想要的结果。

四.解决方案:

理论:如果我这样做,会不会解决问题?

select * from tb_status where status=0 order by id asc limit 1 for update;


五.深入探析

1.我先初始化两条数据:



2.for update 功能1:

首先打开两个查询窗口,窗口1开启事物,执行sql,但是事物不提交,我们看看窗口2的sql执行情况。。。

窗口1



窗口2



可以看到for update 语句如果没有释放锁的话,其他请求是不会得到数据的。。

3.for update 功能2:

下面我修改下sql,看看执行的结果如何:

窗口1



窗口2



这里我们获取到的数据就是id为2的code了。。。

六.实际开发应用

1.如果我们用的是mybatis,那么sql语句这样写就OK了

select  <include refid="allColumns" />
from <include refid="table"/>
<![CDATA[
where XXX...XXX
]]> order by id desc limit 1;


2.事物管理

我们只需要把执行查找和更新放在同一个事物下面管理就OK了

@Transactional(rollbackFor = {Exception.class }, propagation = Propagation.REQUIRED)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  MySQL Java