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

问题由来

假设在一个订单系统中(以火车票订单系统为例),用户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(只对预订的票做悲观锁)

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

还有方案吗……

好了说了这么多,学编程技术哪家强?

时间: 2024-08-04 20:41:47

论火车票订单系统中并发问题和锁机制的探讨的相关文章

Java开源生鲜电商平台-OMS订单系统中并发问题和锁机制的探讨与解决方案(源码可下载)

Java开源生鲜电商平台-OMS订单系统中并发问题和锁机制的探讨与解决方案(源码可下载) 说明:Java开源生鲜电商中OMS订单系统中并发问题和锁机制的探讨与解决方案: 问题由来     假设在一个订单系统中(以火车票订单系统为例),用户A,用户B都要预定从成都到北京的火车票,A.B在不同的售票窗口均同时查询到了某车厢卧铺中.下铺位有空位.用户A正在犹豫订中铺还是下铺,这时用户B果断订购了下铺.当用户A决定订下铺时,系统提示下铺已经被预订,请重新选择铺位.在这个系统场景中,我们来探讨一下,火车票

【巨杉数据库SequoiaDB】巨杉 Tech | 并发性与锁机制解析与实践

01 概述 数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.加锁是实现数据库并发控制的一个非常重要的技术.当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁.加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作. OLTP 场景下通常要求具有很高的并发性.并发事务实际上取决于资源的使用状况,原则上应尽量减少

Mysql事务并发问题,锁机制

Mysql事务并发问题,锁机制 1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约束没有被破坏 持久性:事务的提交结果,将持久保存在数据库中 2.事务并发会产生什么问题 1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了. 例如: 张三的工资为5000,事务A中获取工

MySql 事务,并发问题 ,锁机制 <转>

Mysql事务,并发问题,锁机制 1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约束没有被破坏 持久性:事务的提交结果,将持久保存在数据库中 2.事务并发会产生什么问题 1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了. 例如: 张三的工资为5000,事务A中获取

网上资料笔记总结!!数据库事务并发问题,锁机制和对应的4种隔离级别

数据库事务并发问题 数据库的操作通常为写和读,就是所说的CRUD:增加(Create).读取(Read).更新(Update)和删除(Delete).事务就是一件完整要做的事情.事务是恢复和并发控制的基本单位.事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少.事务在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序.是数据库中各种数据项的一个程序执行单元.事务是用户定义的一个操作序列(多个表同时读写).这些操作要么都做,要么都不做,是一个不可分割的工作单位

高并发情况利用锁机制处理缓存未命中

关于缓存的使用,个人经验还是比较欠缺,对于缓存在应用系统中的使用也只是前几个月在公司实习的时候,简单的使用过,且使用的都是人家把框架搭建好的,至于缓存在并发情况下会产生的一系列问题都已经被框架处理好了,我所做的只是set和get,至于使用时缓存在并发情况下到底会出现什么样的问题,该如何去解决和避免这些问题,没有去深究. 秉着"学而时习之"的态度(T_T自己太懒,厚着脸皮),这两天在鼓捣redis,至于redis的基本使用还是挺简单的,今天要说的是我在这个过程中看到网上博客一直提的关于缓

Mysql事务,并发问题,锁机制-- 幻读、不可重复读(转)

1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约束没有被破坏 持久性:事务的提交结果,将持久保存在数据库中 2.事务并发会产生什么问题 1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了. 例如: 张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5

Mysql事务,并发问题,锁机制

1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约束没有被破坏 持久性:事务的提交结果,将持久保存在数据库中 2.事务并发会产生什么问题 1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了. 例如: 张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5

幂等和高并发在电商系统中的使用

在Java web项目开发中,经常会听到在做订单系统中生成订单的时候,要做幂等性控制和并发控制,特对此部分内容作出总结,在高并发场景下,代码层面需要实现并发控制:但是幂等性,其实更多的是系统的接口对外的一种承诺,承诺一次请求和多次请求会返回同样的数据.关于幂等性将分别从高等代数中的幂等性.HTTP中的幂等性和订单生成系统中的幂等性阐述:并发性控制则提供了分布式锁等方式来对并发场景进行代码实现. 一.幂等性 idempotence  ['a?d?mpo?t?ns] 1.高等代数中关于幂等idemp