müssen Sie bei der Bestellung zwei Punkte beurteilen: 1. Ob der Flash-Sale beginnt oder endet 2. Ob der Lagerbestand ausreicht
Unsere Geschäftslogik lautet also wie folgt folgt
1. Erhalten Sie Coupon-Informationen über die Coupon-ID
2. Stellen Sie fest, ob der Flash-Sale begonnen hat, wenn keine Fehlermeldung zurückgegeben wird. 3. Stellen Sie fest, ob der Flash-Sale beendet ist, und geben Sie eine Fehlermeldung zurück, wenn er beendet ist
4. Wenn es innerhalb der Flash-Sale-Zeit ist, ermitteln Sie, ob der Lagerbestand ausreichend ist.
6.1 Bestell-ID speichern 6.2 Benutzer-ID speichern Der obige Code unter hoher Parallelität. (Mit dem JMX-Tool)
Das Bild unten zeigt, dass zweihundert Threads erstellt und sofort eine Gutscheinanfrage gestellt wurden
Aber wenn wir uns den Aggregationsbericht ansehen, stellen wir fest, dass der Ausreißerwert nur 45,5 % beträgt , was logischerweise 50 % sein sollte. (Da 100 Einheiten auf Lager sind, wurden hier 200 Anfragen gesendet)Wenn man sich die Inventarnummer ansieht, gute Leute, ist sie -9
Die Bestellung hat auch wurden auf 109 Einheiten erhöht, was offensichtlich zu einem Überverkaufsproblem führte.
Schauen Sie sich die Bilder an und sprechen Sie:
Folgen Sie unserem normalen Prozess, das heißt, Thread 1 hat den Bestand überprüft und dann den Bestand abgezogen. Zu diesem Zeitpunkt überprüft Thread 2 den Bestand erneut und zieht den Bestand ab Problem.
Das Problem mit überverkauft liegt darin, dass nach der Überprüfung des Lagerbestands durch Bestellung 1 festgestellt wurde, dass es 1 war, aber bevor der Abzug vorgenommen wurde, überprüfte Thread 2 auch den Lagerbestand und stellte fest, dass es ebenfalls 1 war, und a Es wurde ein Abzug vorgenommen (in Szenarien mit hoher Parallelität)
Dies führt zum Problem des Überverkaufs.
Für diese Art von Problemen mit hoher Parallelität ist die häufigste Lösung: Sperre ~
Pessimistisches Sperren ist relativ einfach, hier wird optimistisches Sperren implementiert.
1. Versionsnummer Die Methode
besteht darin, nach jeder Änderung der Daten eine Versionsnummer hinzuzufügen und am Ende eine Where-Bedingung hinzuzufügen Die Versionsnummer stimmt mit der Version vor der Änderung überein. Auf diese Weise wird die Thread-Sicherheit erreicht Der Bestand ist der Bestand vor der Änderung
Code-Implementierung zur Lösung des Überverkaufsproblems: In der letzten Analyse fügen wir beim Abzug des Bestandes eine Where-Bedingung hinzu, um zu bestimmen, ob der Bestand größer als 0 istpackage com.hmdp.service.impl; import com.hmdp.dto.Result; import com.hmdp.entity.SeckillVoucher; import com.hmdp.entity.VoucherOrder; import com.hmdp.mapper.VoucherOrderMapper; import com.hmdp.service.ISeckillVoucherService; import com.hmdp.service.IVoucherOrderService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.hmdp.utils.RedisIdWorker; import com.hmdp.utils.UserHolder; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.LocalDateTime; /** * <p> * 服务实现类 * </p> * * @author 虎哥 * @since 2021-12-22 */ @Service public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService { @Resource private ISeckillVoucherService iSeckillVoucherService; @Resource private RedisIdWorker redisIdWorker; @Override public Result seckillVoucher(Long voucherId) { //1.获取优惠券信息 SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId); //2.判断是否已经开始 if (voucher.getBeginTime().isAfter(LocalDateTime.now())){ Result.fail("秒杀尚未开始!"); } //3.判断是否已经结束 if (voucher.getEndTime().isBefore(LocalDateTime.now())){ Result.fail("秒杀已经结束了!"); } //4.判断库存是否充足 if (voucher.getStock() < 1) { Result.fail("库存不充足!"); } //5.扣减库存 boolean success = iSeckillVoucherService.update() .setSql("stock = stock-1").eq("voucher_id",voucherId) .update(); if (!success){ Result.fail("库存不充足!"); } //6. 创建订单 VoucherOrder voucherOrder = new VoucherOrder(); //6.1添加订单id Long orderId = redisIdWorker.nextId("order"); voucherOrder.setId(orderId); //6.2添加用户id Long userId = UserHolder.getUser().getId(); voucherOrder.setUserId(userId); //6.3添加优惠券id voucherOrder.setVoucherId(voucherId); save(voucherOrder); //7.返回订单id return Result.ok(orderId); } }
//5.1扣减库存 boolean success = iSeckillVoucherService.update() .setSql("stock = stock-1").eq("voucher_id" , voucherId).gt("stock" ,0) .update();
Das obige ist der detaillierte Inhalt vonSo lösen Sie das Redis-Coupon-Flash-Sale-Problem. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!