SpringBoot:基于悲观锁和数据库乐观锁简单的电商秒杀系统设计实战

1. 数据库设计

假设我们有三张表:user(存储用户信息)、product(存储商品信息)、order(存储订单信息)。以下是简化的表结构:

CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL
);

CREATE TABLE product (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    stock INT NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    start_time TIMESTAMP,
    end_time TIMESTAMP
);

CREATE TABLE order (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT,
    product_id INT,
    quantity INT,
    total_amount DECIMAL(10, 2),
    order_time TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES user(id),
    FOREIGN KEY (product_id) REFERENCES product(id)
);

2. 数据库连接和操作(使用 JDBC)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/your_database";
    private static final String USERNAME = "your_username";
    private static final String PASSWORD = "your_password";

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USERNAME, PASSWORD);
    }
}

用户模块

public class User {
    private int id;
    private String username;
    private String password;

    // Constructor, getters, setters
    // User authentication methods
}

商品模块

import java.math.BigDecimal;
import java.sql.Timestamp;

public class Product {
    private int id;
    private String name;
    private int stock;
    private BigDecimal price;
    private Timestamp startTime;
    private Timestamp endTime;

    // Constructor, getters, setters
    // Methods for managing products
}

订单模块

import java.math.BigDecimal;
import java.sql.Timestamp;

public class Order {
    private int id;
    private int userId;
    private int productId;
    private int quantity;
    private BigDecimal totalAmount;
    private Timestamp orderTime;

    // Constructor, getters, setters
    // Methods for managing orders
}

秒杀逻辑(基于悲观锁和数据库乐观锁的示例)

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.math.BigDecimal;

public class SeckillService {
    public boolean performSeckill(int userId, int productId, int quantity) {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            connection = DatabaseConnection.getConnection();
            connection.setAutoCommit(false);

            // Pessimistic Lock
            String lockProductQuery = "SELECT id, stock FROM product WHERE id = ? FOR UPDATE";
            ps = connection.prepareStatement(lockProductQuery);
            ps.setInt(1, productId);
            rs = ps.executeQuery();

            if (rs.next()) {
                int availableStock = rs.getInt("stock");

                if (availableStock >= quantity) {
                    // Optimistic Lock
                    String checkStockQuery = "SELECT stock FROM product WHERE id = ?";
                    ps = connection.prepareStatement(checkStockQuery);
                    ps.setInt(1, productId);
                    rs = ps.executeQuery();

                    if (rs.next()) {
                        int currentStock = rs.getInt("stock");

                        if (currentStock >= quantity) {
                            BigDecimal price = getProductPrice(productId);
                            BigDecimal totalAmount = price.multiply(BigDecimal.valueOf(quantity));

                            // Create order
                            String createOrderQuery = "INSERT INTO order (user_id, product_id, quantity, total_amount, order_time) VALUES (?, ?, ?, ?, ?)";
                            ps = connection.prepareStatement(createOrderQuery);
                            ps.setInt(1, userId);
                            ps.setInt(2, productId);
                            ps.setInt(3, quantity);
                            ps.setBigDecimal(4, totalAmount);
                            ps.setTimestamp(5, new Timestamp(System.currentTimeMillis()));

                            int affectedRows = ps.executeUpdate();

                            if (affectedRows > 0) {
                                // Reduce product stock
                                String reduceStockQuery = "UPDATE product SET stock = stock - ? WHERE id = ?";
                                ps = connection.prepareStatement(reduceStockQuery);
                                ps.setInt(1, quantity);
                                ps.setInt(2, productId);
                                ps.executeUpdate();

                                connection.commit();
                                return true; // Seckill successful
                            }
                        }
                    }
                }
            }
            connection.rollback();
            return false; // Seckill failed due to stock constraints
        } catch (SQLException e) {
            // Handle exceptions and rollback transaction
        } finally {
            // Close resources
        }
    }

    private BigDecimal getProductPrice(int productId) {
        // Fetch product price from database or cache
    }
}
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

public class ProductService {
    private Map<Integer, BigDecimal> productPrices; // 假设缓存商品价格的数据结构为 Map,key 为商品 ID,value 为商品价格

    public ProductService() {
        this.productPrices = new HashMap<>();
        // 从数据库或其他来源加载商品价格到缓存中
        loadProductPrices();
    }

    private void loadProductPrices() {
        // 从数据库加载商品价格,并放入缓存中
        // 示例:假设从数据库加载商品价格
        productPrices.put(1, BigDecimal.valueOf(99.99)); // 商品ID为1的价格为99.99
        productPrices.put(2, BigDecimal.valueOf(49.99)); // 商品ID为2的价格为49.99
        // 其他商品价格的加载
    }

    public BigDecimal getProductPrice(int productId) {
        // 从缓存中获取商品价格
        BigDecimal price = productPrices.get(productId);
        
        if (price == null) {
            // 如果缓存中没有该商品的价格,则从数据库获取并放入缓存
            price = fetchPriceFromDatabase(productId);
            if (price != null) {
                productPrices.put(productId, price);
            }
        }
        return price;
    }

    private BigDecimal fetchPriceFromDatabase(int productId) {
        // 模拟从数据库获取商品价格的操作
        // 实际中可能需要连接数据库并执行查询操作
        // 返回商品价格
        if (productId == 1) {
            return BigDecimal.valueOf(99.99); // 假设商品ID为1的价格为99.99
        } else if (productId == 2) {
            return BigDecimal.valueOf(49.99); // 假设商品ID为2的价格为49.99
        }
        // 其他商品价格的获取
        return null;
    }
}

以上代码只是一个简化的示例,实际的秒杀系统需要更多功能和安全性措施,比如并发控制、防止超卖、接口安全性等。此外,还需要框架来处理前端交互和后端业务逻辑,比如使用Spring框架来构建整个应用。

对于一个完整的实战系列,建议你查阅相关的课程、书籍或在线教程,深入学习并实践这些概念和技术。

你可能感兴趣的:(数据库,spring,boot)