前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >订单系统中并发问题和锁机制的探讨

订单系统中并发问题和锁机制的探讨

作者头像
精讲java
发布2018-07-03 17:36:51
1.6K3
发布2018-07-03 17:36:51
举报
文章被收录于专栏:平凡文摘平凡文摘

问题由来

假设在一个订单系统中(以火车票订单系统为例),用户A,用户B都要预定从成都到北京的火车票,A、B在不同的售票窗口均同时查询到了某车厢卧铺中、下铺位有空位。用户A正在犹豫订中铺还是下铺,这时用户B果断订购了下铺。当用户A决定订下铺时,系统提示下铺已经被预订,请重新选择铺位。在这个系统场景中,我们来探讨一下,火车票系统是怎样处理并发事件以及怎么利用锁机制来避免重复订票的。

设想的方案

方案1:

为了避免重复订票,大部分人会想到在做订票操作前,去数据库查询该铺位是否已经被预订,假设“铺位”数据库表增加标记字段FLAG(空闲:0;已预订:1),如果查询到铺位的FLAG字段值为1,那么预订就不成功,如果为0就成功预订,并把FLAG置为1。这种方案如果在业务量很少的系统中,或许可行。但业务量较大时,特别是火车票这样的业务量,就会出现问题。问题在,当用户A、用户B同时对同一铺位预订时,虽说是“同时”,但对于数据库操作来说一定是有先后顺序的,假设A在查询该铺位的FLAG时,值为0,准备预订并将值设为1,而与此同时B已经预订成功,并已将FLAG设为1。而A因为没有即时查询到FLAG=1,因此也预订成功,又将FLAG设为1。

A FLAG=0 时刻=T1 (查询)

B FLAG=0 时刻=T2 (查询)

B FLAG=1 时刻=T3 (更新)

A FLAG=1 时刻=T4 (更新)

这样就造成了重复订票,在购票高峰期,使用这样的方案,重复订票不可避免。

方案2:

我们想到了利用数据库的悲观锁来解决这个问题,设想假如用户A查询到想预订的票,用户B根本都查询不到,只有A一个人能看到,那是不是没有重复订票的可能了,因为压根没人跟他抢。可以这样实现这个方案:

select * from table where …… for update skip locked,该语句是查询用户指定条件的票信息,并加锁(for update),如果有记录已经被锁则自动跳到下一条记录(skip locked),这样谁先查询谁就可以慢慢的考虑要上铺还是下铺。但火车票系统是这样做的吗?显然不是,因为这样用户体验太不好,票实际还很多,但确看不到买不到,这显然不合理。

方案3:

我们又想到了从程序层面来解决并发问题,最简便的方式是利用synchronized来处理,但我们要知道一个大型系统必然是集群方式部署的,synchronized只能解决单节点环境的并发问题,要解决此问题还是必须依赖全局性的锁机制。

方案4:

既然又回到了在数据库上加锁,我们又想一下如果我们在查询时,使用乐观锁,但在预订之前使用悲观锁会怎样呢?例如我们查询时:

select * from table where ……

用户A、用户B都查询到了相同的票信息(中铺和下铺),用户A或用户B在预订时做一次悲观锁:

select * from table where …… for update(只对预订的票做悲观锁)

此时后者在预订时,无法获取该记录的锁,自然就无法预订,避免了重复预订的问题。

还有方案吗……

出处:http://www.cnblogs.com/leefreeman/p/3711470.html

版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。

转载声明:本文转载自「精讲JAVA」。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 平凡文摘 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档