设计抢购业务时,请务必注意这4个要点

中科医院曝光资质 https://m-mip.39.net/czk/mipso_5153159.html

作者:香鱼

全文共字5图,阅读需要8分钟

————/BEGIN/————

案例:马上就到双十一了,上级给我安排了一个秒杀抢购的活动,让我设计一个方案,那我应该如何下手呢?

页面上面的设计,这里我就不多说了,各大网站上都有很多案例了!

现在我重点来讲一下需要注意的几点:

一、超卖问题

假如你的库存有10,现在3个用户来购买,a用户购买3个,b用户购买5个,c用户购买3个,合起来就是准备购买11个。

如果三个用户是同时并发购买,会出现怎样的情况呢?

每个用户进行减库存的时候,数据库都会去修改一下数据,如下:updategoodssetamount=amount-购买数量wheregoods_id=xxx。

mysql会锁定这一行数据(使用innodb存储引擎),数据库加的是排他锁。

根据排他锁的特点:其他线程不能读、不能写此行数据。

排他锁情况下,那么其他用户就是等待状态了。

1.a用户执行update的时候,锁定库存数据。update执行完毕后,减去了3个后,mysql自动释放锁。

2.b用户执行,减去了5个。此时,已经卖掉8个库存了,库存数为2了。

3.但是c用户接着执行,Updategoodssetamount=amount-1wheregoods_id=xxx。

结果库存数量变成-1了。

思考:把库存数量字段的类型,设计成正数类型,不允许出现负数,会怎么样呢?

测验结果:数据库会直接报错,通不过。

解决办法:只有库存数量,大于或等于购买数量的时候,才能去减库存;其他情况,提示信息,库存不足。

二、并发的问题

为了更好的理解并发和同步,我们需要先明白两个重要的概念:同步和异步。

同步和异步的区别和联系:

所谓同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是出于阻塞的,只有接收到返回的值或消息后才往下执行其它的命令。

异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。

同步在一定程度上可以看做是单线程,这个线程请求一个方法后就待这个方法给他回复,否则他不往下执行。异步在一定程度上可以看做是多线程的,请求一个方法后,就不管了,继续执行其他的方法。

如何处理并发和同步?

首先需要明白,锁机制有两个层面:

一种是代码层次上的,如:java中的同步锁,典型的就是同步关键字synchronized,这里我不在做过多的讲解;

另外一种是数据库层次上的,比较典型的就是悲观锁和乐观锁。这里我们重点讲解的就是悲观锁(传统的物理锁)和乐观锁。

悲观锁(PessimisticLocking):

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。

悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

第一种问题中描述的超卖现象,其实是并发抢购时出现的情况。用到的是数据库内带的加排他锁方式,阻止了其他线程读取、访问数据,这样等待的时间就比较长。而业界一般的解决是使用乐观锁的办法来解决:使用数据库的乐观锁是通用解决办法。

乐观锁:

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。

但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。

如:一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时(如更改用户帐户余额),如果采用悲观锁机制,也就意味着整个操作过程中(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态。

可以想见:如果面对几百上千个并发,这样的情况将导致怎样的后果。

乐观锁机制在一定程度上解决了这个问题。

通俗说就是:修改数据的时候,不给数据加锁。

乐观锁意思是不锁定表的情况下,利用业务的控制来解决并发问题,这样即保证数据的并发可读性又保证保存数据的排他性,保证性能的同时解决了并发带来的脏数据问题。

所以很多情况下都会采用乐观锁来解决业务上的问题。

高并发的解决方法主要有以下几点:

(1)前台优化

减少


转载请注明:http://www.aierlanlan.com/rzfs/5331.html