成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

日活3kw的實際庫存業務場景中的超賣到底怎么解決的

數據庫
超賣問題的根源在于并發操作,因此解決超賣問題實質上就是解決并發問題。在上述情況中,關鍵在于確保庫存扣減過程的原子性和有序性。

這個問題其實可以說是隨便一百度幾乎可以出來全是解決方案,其實超賣問題在實際業務場景中是十分復雜的。沒有什么絕對的解決方案。都是因人而異的。

"超賣"是指商品售出數量超過實際庫存量的情況。通常在處理商品庫存扣減時,我們會先檢查庫存是否充足,如果足夠則進行扣減,否則直接返回下單失敗。

然而,在高并發環境下,可能出現以下情形:

在高并發情況下,當兩個并發線程同時查詢庫存時,假設數據庫中庫存僅剩1個,兩個線程都獲得了1的庫存量。在經過庫存校驗后,它們分別開始執行庫存扣減操作,最終導致庫存變成負數。

這種情況是高并發環境下典型的超賣問題。

超賣問題的根源在于并發操作,因此解決超賣問題實質上就是解決并發問題。在上述情況中,關鍵在于確保庫存扣減過程的原子性和有序性。

  • 原子性指的是庫存查詢、庫存判斷和庫存扣減這一系列操作作為一個不可分割的整體,不會被中斷,也不會被其他線程同時執行。這確保了操作的完整性和一致性。
  • 有序性則要求多個并發操作按照一定的順序執行,避免出現競爭條件,從而保證數據的準確性和正確性。

通過確保庫存扣減操作的原子性和有序性,可以有效解決高并發環境下的超賣問題,保障系統的穩定性和可靠性。

一、實現方案:數據庫

從三個角度考慮實現:

  • 數據庫層面的悲觀鎖
  • 數據庫層面的樂觀鎖
  • 依賴數據庫執行引擎的順序執行機制

以上三個角度簡單來說:在處理庫存扣減時,常見的方法是通過數據庫操作實現。確保操作的原子性和有序性通常可以通過加鎖實現,無論是悲觀鎖還是樂觀鎖都可以達到這個目的。

1.悲觀鎖的實現方式

-- 開始事務
BEGIN;

-- 查詢商品信息并加鎖
SELECT quantity FROM items WHERE id = 1 FOR UPDATE;

-- 修改商品數量為2
UPDATE items SET quantity = 2 WHERE id = 1;

-- 提交事務
COMMIT;

注意:

在前述討論中,我們提到了使用SELECT...FOR UPDATE會對數據進行鎖定,但需要注意鎖的級別。在 MySQL InnoDB 中,默認使用行級鎖。行級鎖是基于索引的,如果一條 SQL 語句沒有使用索引,那么不會使用行級鎖,而會使用表級鎖將整個表鎖定。因此,這一點需要引起注意。

然而,使用悲觀鎖可能會導致請求阻塞和排隊,在高并發情況下可能對數據庫造成負擔。樂觀鎖則通過版本號等方式控制順序執行,但在高并發環境下可能會出現大量失敗操作,不適合高并發場景,因為在更新過程中也需要加行級鎖,可能會導致阻塞。

2.樂觀鎖的實現方式

在MySQL中,樂觀鎖主要通過CAS(Compare and Swap)機制來實現,通常通過版本號來實現。CAS是一種樂觀鎖技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能成功更新變量的值,而其他線程會失敗。失敗的線程不會被掛起,而是會被告知在這次競爭中失敗,并可以再次嘗試。

舉例來說,對于之前提到的庫存扣減問題,通過樂觀鎖可以實現以下操作:

//查詢出商品信息,quantity = 3
select quantity from items where id=1

//根據商品信息生成訂單
//修改商品quantity為2
update items set quantity=2 where id=1 and quantity = 3;

盡管如此,即使不使用鎖也是可行的。可以依賴數據庫執行引擎的順序執行機制,只需確保庫存不會變為負數。這種情況下,可以通過巧妙設計的SQL語句來實現操作的原子性和有序性。

3.數據庫執行引擎的實現方式

舉例來說,假設有一張名為"inventory"的表,其中包含"product_id"和"stock"字段,可以通過以下SQL語句來實現庫存扣減:

UPDATE inventory 
SET stock = stock - 1 
WHERE product_id = 'your_product_id' AND stock > 0;

這樣的SQL語句能夠確保在庫存大于0的情況下進行扣減,避免庫存變為負數。通過這種方式,可以在不加鎖的情況下有效地管理庫存扣減操作。

有人可能會覺得數據庫執行引擎的實現方式挺好的。然而,這種解決方案并不理想。實際上,這種方式與樂觀鎖方案的缺點相同,都完全依賴于數據庫。在高并發情況下,多個線程同時更新庫存時可能會導致阻塞。這不僅會導致操作速度變慢,還可能給數據庫帶來壓力。

通常情況下,MySQL的熱點行更新最多也只能承受200-300個并發更新。如果需要更高的并發處理能力,一種方法是提升硬件水平,另一種方法是進行一些技術改造,比如采用inventory hint的方式。

說到這里,數據庫層面的超賣的解決實現方案也就聊的差不多了。

二、實現方式:Redis

我們可以利用Redis的單線程執行特性,結合Lua腳本執行過程中的原子性保障,實現庫存扣減操作。通過在Redis中使用如下Lua腳本:

local key = KEYS[1] -- 商品的鍵名
-- 獲取商品當前的庫存量
local remaining_stock = tonumber(redis.call("GET", key))

local quantity_to_reduce = tonumber(ARGV[1])  -- 扣減的數量

-- 如果庫存足夠,則減少庫存并返回新的庫存量
if remaining_stock >= quantity_to_reduce then
    redis.call("DECRBY", key, quantity_to_reduce)
    return "Stock reduced successfully"
else
    return "Insufficient stock"
end

通過先從Redis中獲取當前剩余庫存,然后進行足夠性檢查并執行扣減操作,可以有效避免并發問題。由于Lua腳本在執行過程中不會被中斷,且Redis是單線程執行的,因此在腳本中進行這些操作可以確保原子性和有序性。這種方法結合了Redis的高性能和分布式緩存特性,使得使用Lua腳本扣減庫存非常高效。

三、我們實際項目中如何處理超賣的

在實際應用中,通常會結合使用數據庫和Redis兩種方案來實現庫存扣減操作。一種常見的做法是首先利用Redis進行扣減操作以應對高并發流量,然后將扣減結果同步到數據庫中,實現扣減并進行持久化存儲,以防止Redis宕機導致數據丟失。

具體流程如下:

  • 首先在Redis中進行庫存扣減操作,然后發送一個消息到消息隊列(MQ)。
  • 消費者接收到消息后,執行數據庫中的真正庫存扣減以及其他業務邏輯操作。

Redis扣減操作示例代碼:

可以使用上述提到的Lua腳本方式,或者采用如下Redisson方式

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class InventoryConsumer {

    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        RedissonClient redisson = Redisson.create(config);

        RLock lock = redisson.getLock("inventory_lock");

        try {
            lock.lock();

            // 執行庫存扣減及其他業務邏輯操作
            // 例如:更新數據庫中的庫存信息
            // 注意:在鎖內執行扣減操作

        } finally {
            lock.unlock();
            redisson.shutdown();
        }
    }
}

消費者示例代碼:

public class InventoryConsumer {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        Connection conn = null;

        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database", "user", "password");

            jedis.subscribe(new JedisPubSub() {
                @Override
                public void onMessage(String channel, String message) {
                    // 在收到消息時執行數據庫操作,進行庫存扣減及其他業務邏輯
                    try {
                        Statement stmt = conn.createStatement();
                        stmt.executeUpdate("UPDATE inventory SET stock = stock - 1 WHERE product_id = '123'");
                        conn.commit();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }, "inventory_update");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            jedis.close();
        }
    }
}

通過結合使用Redis和數據庫,可以充分發揮它們各自的優勢,實現高效的庫存管理并確保數據的一致性和持久性。

這種方法確實有助于確保Redis中的數據與數據庫中的數據最終保持一致,同時也有助于避免超賣的情況發生。然而,存在一個潛在問題,即可能導致少賣的情況發生。

四、少賣的解決方案

在上述流程中,如果第一步成功執行,導致Redis中的庫存成功扣減,但隨后的第二步消息未能成功發送,或者在后續消費過程中消息丟失或失敗,就可能出現Redis中庫存減少而數據庫庫存未減少的情況,從而導致實際業務操作未能發生。這種情況會導致Redis中出現多扣的情況,進而引發少賣的問題。

為了解決這類問題,需要引入一種對賬機制,實施準實時核對,及時發現并處理這類情況。如果發現存在較大的少賣問題,需要將這些庫存重新添加回去。

在許多成熟的電商公司中,無論之前的方案多么完善,這種對賬系統都是不可或缺的。及時進行核對,發現超賣、少賣等問題至關重要。

一個簡單的示例是,在消費者處理消息時,記錄每次庫存變化的日志,包括扣減和增加操作,然后定期對比Redis中的庫存和數據庫中的庫存,檢查是否存在不一致的情況。如果發現多扣或少賣的情況,可以根據日志記錄進行修正。

這種對賬機制可以幫助保證系統的數據一致性,并及時發現并糾正潛在的問題,確保業務操作的準確性和穩定性。

綜上所述可得沒有完美的解決方案,引入新的中間件總會面臨的的問題。這就需要根據實際業務進行權衡了。

責任編輯:趙寧寧 來源: 碼上遇見你
相關推薦

2024-03-13 08:10:40

SQL優化索引

2023-11-17 16:06:14

2017-06-15 08:02:02

庫存扣減查詢

2010-06-07 14:50:50

jsp MySQL

2024-05-20 09:52:55

自動駕駛場景

2023-03-13 00:24:21

微軟活躍用戶OpenAI

2019-05-28 13:50:27

MySQL幻讀數據庫

2024-08-27 08:35:43

JavaScriptPromise模式

2020-07-27 10:51:36

機器學習數據人工智能

2024-09-10 10:42:27

2017-08-24 16:48:22

銳捷

2021-09-13 10:31:02

Java原子

2022-11-24 10:43:33

2022-10-17 09:39:13

JDK虛擬線程

2024-04-26 00:28:14

異地多活架構

2010-05-25 11:24:34

MySQL 亂碼

2010-07-27 09:59:32

DB2設計

2018-07-17 16:18:50

登陸注冊手機驗證業務邏輯

2009-11-23 17:56:45

業務路由器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩中文字幕av | 91最新入口 | 精品一区二区视频 | 日韩一区二区三区在线观看 | 日韩在线中文字幕 | 日本一区二区三区四区 | 国产一区二区三区在线 | 亚洲男人天堂av | 爱爱免费视频网站 | 99精品久久 | 9999视频| 99视频精品 | 国精品一区 | 欧美一区二不卡视频 | 国产99视频精品免费视频7 | 国产一区二区视频免费在线观看 | 久久首页 | 亚洲国产黄色av | 亚洲欧洲激情 | 欧美va大片 | 日本一区视频在线观看 | 久久精品中文字幕 | 免费人成激情视频在线观看冫 | 国产a区 | 婷婷色在线播放 | 亚洲在线日韩 | av久久| 91看片网址| 午夜不卡福利视频 | 国产精品一区二区av | 91国内在线观看 | 久久精品国产99国产 | 一区二区三区亚洲 | 国产精品3区 | 国产精品美女久久久久 | 少妇一级淫片免费放播放 | 麻豆精品一区二区三区在线观看 | 日韩a视频 | 成人在线免费电影 | 国产蜜臀97一区二区三区 | 在线免费看黄 |