Heim  >  Artikel  >  Datenbank  >  So lösen Sie das Redis-Coupon-Flash-Sale-Problem

So lösen Sie das Redis-Coupon-Flash-Sale-Problem

王林
王林nach vorne
2023-05-28 14:52:171175Durchsuche

1 Um die Coupon-Flash-Sale-Funktion zu implementieren

So lösen Sie das Redis-Coupon-Flash-Sale-Problem

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

So lösen Sie das Redis-Coupon-Flash-Sale-Problem

Die Bestellung hat auch wurden auf 109 Einheiten erhöht, was offensichtlich zu einem Überverkaufsproblem führte.

Also, warum tritt dieses Problem auf?

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.

So lösen Sie das Redis-Coupon-Flash-Sale-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)

So lösen Sie das Redis-Coupon-Flash-Sale-Problem

Dies führt zum Problem des Überverkaufs.

Für diese Art von Problemen mit hoher Parallelität ist die häufigste Lösung: Sperre ~ So lösen Sie das Redis-Coupon-Flash-Sale-Problem

Aber Sperren umfassen pessimistische Sperren und optimistische Sperren.

Pessimistisches Sperren bedeutet einfach: Ich denke, der Thread wird definitiv passieren, und dann nimmt jeder die Sperre vor der Operation. Nachdem Sie mit der Ausführung fertig sind, ist der nächste an der Reihe (serielle Ausführung)

Optimistisches Sperren: Es ist optimistisch (Es wird davon ausgegangen, dass Thread-Sicherheit niemals auftritt.) Solange vor jeder Datenänderung beurteilt wird, ob andere Threads die Daten geändert haben, um die Thread-Sicherheit sicherzustellen.

Pessimistisches Sperren ist relativ einfach, hier wird optimistisches Sperren implementiert. So lösen Sie das Redis-Coupon-Flash-Sale-Problem

Der Schlüssel zum optimistischen Sperren besteht darin, festzustellen, ob die durch die vorherige Abfrage erhaltenen Daten geändert wurden.

Warme Erinnerung: Die Daten in der Tabelle links sind alle Daten nach der Ausführung des Threads 1~

So lösen Sie das Redis-Coupon-Flash-Sale-Problem1. 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 ist

package 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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen