欧美1区2区3区激情无套,两个女人互添下身视频在线观看,久久av无码精品人妻系列,久久精品噜噜噜成人,末发育娇小性色xxxx

Java有什么項目推薦的嗎?電商功能設計

項目經歷第三期。。。。。。項目經歷第三期。。。。。。項目經歷第三期。。。。。。

大家好,我是南哥。

一個Java學習與進階的領路人,跟著南哥我們一起Java成長。

文章目錄

  1. 電商功能設計
    1. 商品表設計
    2. 商品列表
    3. 商品詳情
    4. 商品下單
    5. 重點:秒殺搶購

好久之前就想寫這么一篇商品功能設計,這幾天得空把坑給填了,給南友們多一個 "項目亮點" 的參考。

1. 電商功能設計

1.1 商品表設計

面試官:數據庫表你怎么設計的?

南哥先給出電商業(yè)務最基礎的幾個表設計。隨著用戶量的激增,肯定的是業(yè)務復雜性會逐日遞增,你會發(fā)現(xiàn)簡簡單單的一個表,不知不覺多出了很多奇奇怪怪的字段。

(1)商品表

CREATE TABLE products (
    product_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL,
    stock INT DEFAULT 0,
    category_id INT,
    status ENUM('active', 'inactive', 'deleted') DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (category_id) REFERENCES product_categories(category_id)
);

(2)商品分類表

CREATE TABLE product_categories (
    category_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    parent_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (parent_id) REFERENCES product_categories(category_id)
);

(3)用戶購物車表

CREATE TABLE shopping_carts (
    cart_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT DEFAULT 1,
    added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    FOREIGN KEY (product_id) REFERENCES products(product_id)
);

(4)訂單表

CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    total_price DECIMAL(10, 2) NOT NULL,
    status ENUM('pending', 'completed', 'cancelled') DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

1.2 商品列表

面試官:那商品列表接口怎么保證可用性?

商品列表在電商APP有多種形式,例如:熱門商品列表、查詢條件商品列表、用戶推薦商品列表。

(1)熱門商品列表

特別針對第一種形式,熱門商品列表要重點加上緩存,畢竟該列表所有用戶打開APP都需要顯示出來,可以把該接口歸類為高并發(fā)設計接口。

熱門商品有一個特點,商品的更新速度快,可能某個商品半小時還在熱門,下一秒突然不見。

這里我們采用Redis分布式緩存,后臺配置熱門商品時更新分布式緩存,而熱門商品列表接口直接查詢Redis,不把壓力落到數據庫。

// 后臺配置熱門商品時更新分布式緩存,而熱門商品列表接口直接查詢Redis
public List<Product> getHotProductList() {
    // 從Redis緩存獲取熱門商品列表
    List<Product> hotProducts = redisTemplate.opsForList().range("hot_products", 0, -1);
    if (hotProducts == null || hotProducts.isEmpty()) {
        // 如果緩存為空,從數據庫查詢,并更新緩存
        hotProducts = productService.fetchHotProductsFromDB();
        redisTemplate.opsForList().rightPushAll("hot_products", hotProducts);
    }
    return hotProducts;
}

另外需要把熱門商品列表緩存到APP端,不至于每次返回主頁面就調用一次接口查詢。APP端緩存接口設置短些,例如1 分鐘,畢竟上文有提到熱門商品更新速度是比較快的!

(2)查詢條件商品列表

用戶的查詢條件多種多樣,我們可以把用戶查詢關鍵詞通過埋點記錄下來,要求運營給出熱度最高的商品查詢關鍵詞。

針對熱門關鍵詞查詢,把查詢結果進行緩存。當然整個查詢結果會很大,我們設置對前幾頁進行緩存。

緩存放在哪?

這里我們仍然放在Redis分布式緩存。有人可能會說放到后端本地緩存?MyBatis一級、二級緩存的坑或許他還沒遇到,MyBatis一級緩存作用于SqlSession對象,二級緩存作用于Mapper對象。這造成了各個后端服務的本地緩存不同,每次查詢的結果都不相同。

當然有些業(yè)務可以用到,例如閱讀量這些用戶不太在意的的數據可以用本地緩存。

// 查詢條件商品列表
public List<Product> getProductsByQuery(String query, int page) {
    String cacheKey = "query_products:" + query + ":page" + page;
    List<Product> products = redisTemplate.opsForList().range(cacheKey, 0, -1);
    if (products == null || products.isEmpty()) {
        // 如果緩存為空,從數據庫查詢,并更新緩存
        products = productService.fetchProductsByQueryFromDB(query, page);
        redisTemplate.opsForList().rightPushAll(cacheKey, products);
        // 緩存有效期為10分鐘
        redisTemplate.expire(cacheKey, 10, TimeUnit.MINUTES);
    }
    return products;
}

另一個問題,查詢結果變化怎么辦?

這里我們設置一個定時任務,每隔一段時間更新 "查詢條件商品列表" 的緩存結果。

// 定時任務更新緩存
@Scheduled(fixedRate = 600000)
public void updateProductsCache() {
    // 重新從數據庫獲取數據并更新緩存
    List<String> hotQueries = analyticsService.getHotQueries();
    for (String query : hotQueries) {
        List<Product> products = productService.fetchProductsByQueryFromDB(query, 1); // 僅示例:更新第一頁數據
        String cacheKey = "query_products:" + query + ":page1";
        redisTemplate.delete(cacheKey);
        redisTemplate.opsForList().rightPushAll(cacheKey, products);
         // 重設緩存有效期
        redisTemplate.expire(cacheKey, 10, TimeUnit.MINUTES);
    }
}

1.3 商品詳情

面試官:商品詳情為什么要加緩存?

商品詳情的特點是更新頻率慢,另外用戶的操作習慣是:會不斷退出重進,反復瀏覽某個商品的詳情頁。

猜猜他們在干嘛,用戶在反復對比不同商品,勸說自己究竟要買哪一個,畢竟強迫癥大家都有的。

基于以上的用戶行為、商品詳情特點,我們可以把商品詳情緩存到APP端。

1.4 商品下單

面試官:下單邏輯怎么保證安全性?

電商業(yè)務的訂單記錄表、商品下單接口是最重要的核心模塊,畢竟這一塊涉及到了業(yè)務賺錢的核心。

(1)校驗功能

用戶從APP端點擊下單按鈕,后端服務要走一套怎么樣的流程?首先我們需要先進行校驗。

  1. 用戶身份校驗
  2. 用戶余額校驗
  3. 商品校驗
  4. 商品庫存校驗

(2)防重復提交

再者,對于下單接口需要添加防重復提交限制,這里可以有多種方案。舉個例子,采用Redis分布式鎖方案,Redis分布式鎖的key設置與用戶、商品id相關。

# Redis分布式鎖的key
lock:order:{uid}:{product_id}

用戶下單某一個商品,會獲取Redis分布式鎖。對于同一個商品,在前一個商品的邏輯沒有處理完成時,不能進行下一次下單請求。

防重復提交的作用主要是防止用戶誤觸,或者同一時間多個重復下單請求造成的數據異常。

(3)事務控制

對于整個下單的流程,包括庫存的減少、用戶扣費、訂單表的創(chuàng)建都應該包含在同一個MySQL事務中,一旦流程中的任何一個邏輯出錯,則進行回滾。

(4)異步處理

對于下單成功后的其他操作,例如下單成功信息通知用戶等,可以使用任務隊列的形式異步去執(zhí)行,減少下單接口的耗時。

// 用戶下單接口
public Order placeOrder(int userId, int productId, int quantity) throws Exception {
    // 獲取分布式鎖
    String lockKey = "lock:order:" + userId + ":" + productId;
    if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS)) {
        throw new Exception("下單過于頻繁,請稍后再試");
    }

    try {
        // 檢查用戶、商品及庫存
        userService.verifyUser(userId);
        Product product = productService.verifyProduct(productId);
        inventoryService.checkInventory(productId, quantity);

        // 開始事務
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

        try {
            // 減庫存,扣費,生成訂單
            inventoryService.decreaseInventory(productId, quantity);
            userService.debitUserAccount(userId, product.getPrice().multiply(new BigDecimal(quantity)));
            Order order = orderService.createOrder(userId, productId, product.getPrice(), quantity);
            
            transactionManager.commit(status); // 提交事務
            return order;
        } catch (Exception e) {
            transactionManager.rollback(status); // 回滾事務
            throw e;
        }
    } finally {
        redisTemplate.delete(lockKey); // 釋放鎖
    }
}

1.5 重點:秒殺搶購

面試官:你會怎么設計秒殺搶購功能?

我們可以把秒殺搶購看成是商品下單的特殊場景。秒殺搶購的并發(fā)量高,庫存有限,且秒殺商品的頁面會獨立出來,不會和其他商品頁面耦合在一起。

基于以上簡單的梳理,我們可以這么設計來保證秒殺場景的穩(wěn)定性。

(1)秒殺頁面靜態(tài)化

把秒殺商品頁面設置為靜態(tài)化,當用戶刷新頁面時,只需要從服務器獲取基礎后端數據進行填充。另外當用戶點擊秒殺按鈕后,前端把按鈕進行置灰,減少用戶的請求。

(2)下單限制

很多程序員的初始設計會把所有請求都進入下單接口流程,完全沒必要!??!

如果秒殺庫存只有10,在下單接口前面,我們可以設置一個過濾攔截,只有前50個用戶才會進入下單流程,拒絕其他用戶的下單請求,其他用戶甚至不需要進行下單的流程。

后續(xù)在由這50個用戶搶奪這10個商品庫存。

// 決定是否讓用戶進入搶購流程
public class SeckillController {

    @Autowired
    private KafkaTemplate<String, SeckillOrderRequest> kafkaTemplate;

    public ResponseEntity<String> placeSeckillOrder(int userId, int productId) {
        String queueName = "seckill_orders";
        String lockKey = "seckill:availability:" + productId;
        // 檢查是否還有秒殺資格
        Long rank = redisTemplate.opsForValue().increment(lockKey);
        if (rank == null || rank > 50) {
            return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("抱歉,秒殺名額已滿。");
        }

        // 創(chuàng)建秒殺請求
        SeckillOrderRequest request = new SeckillOrderRequest(userId, productId);

        // 發(fā)送到Kafka隊列
        kafkaTemplate.send(queueName, request);
        return ResponseEntity.ok("您的秒殺請求已接收,正在處理中,請耐心等待結果。");
    }
}

(3)下單請求任務化

把每一個下單請求都抽象為一個Kafka隊列任務,任務一個個執(zhí)行,減少系統(tǒng)的瞬時壓力。

// 出來下單隊列任務
@Service
public class SeckillOrderConsumer {

    @Autowired
    private OrderService orderService;

    @Autowired
    private ProductService productService;

    @Autowired
    private InventoryService inventoryService;

    @KafkaListener(topics = "seckill_orders", groupId = "seckill_group")
    public void consume(SeckillOrderRequest request) {
        try {
            // 檢查庫存
            if (!inventoryService.checkInventory(request.getProductId(), 1)) {
                throw new Exception("庫存不足");
            }
            // 下單處理
            Order order = orderService.createSeckillOrder(request.getUserId(), request.getProductId(), 1);
            // 其他邏輯處理
            notifyUser(order);
        } catch (Exception e) {
            // 處理失敗邏輯
            System.out.println("秒殺處理失敗:" + e.getMessage());
        }
    }

    private void notifyUser(Order order) {
        // 通知用戶秒殺結果
    }
}

創(chuàng)作不易,不妨點贊、收藏、關注支持一下,各位的支持就是我創(chuàng)作的最大動力????

#java##秋招##面試##項目##實習#
全部評論

相關推薦

03-25 16:22
南華大學 Java
不敢追175女神:你是打了上千個招呼吧???
點贊 評論 收藏
分享
評論
點贊
收藏
分享

創(chuàng)作者周榜

更多
??途W
??推髽I(yè)服務