SpringBoot:基于悲观锁和数据库乐观锁简单的电商秒杀系统设计实战
2023-12-27 10:25:39
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框架来构建整个应用。
对于一个完整的实战系列,建议你查阅相关的课程、书籍或在线教程,深入学习并实践这些概念和技术。
文章来源:https://blog.csdn.net/weixin_43709538/article/details/135236252
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!