当前位置: 首页 > news >正文

预留库存的实现

1. 实体类

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.sql.Timestamp;@Data
@TableName("products")
public class Product {private Long id;private String name;private int stock;
}@Data
@TableName("shopping_carts")
public class ShoppingCart {private Long id;private Long userId;private Long productId;private int quantity;private Timestamp reservedTime;
}

2. Mapper 接口

在 ProductMapper 中添加自定义的库存更新方法:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;@Mapper
public interface ProductMapper extends BaseMapper<Product> {@Update("update products set stock = stock - #{quantity} where id = #{productId} and stock >= #{quantity}")int reduceStock(Long productId, int quantity);@Update("update products set stock = stock + #{quantity} where id = #{productId}")int increaseStock(Long productId, int quantity);
}@Mapper
public interface ShoppingCartMapper extends BaseMapper<ShoppingCart> {java.util.List<ShoppingCart> selectByReservedTimeBefore(java.sql.Timestamp timestamp);
}

3. Mapper XML 文件(可选)

ShoppingCartMapper.xml 文件保持不变:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ShoppingCartMapper"><select id="selectByReservedTimeBefore" resultType="com.example.demo.entity.ShoppingCart">SELECT * FROM shopping_carts WHERE reserved_time < #{timestamp}</select>
</mapper>

4. 服务类

修改 ShoppingCartService 中的 addToCart 和 releaseExpiredReservations 方法:

import com.example.demo.entity.Product;
import com.example.demo.entity.ShoppingCart;
import com.example.demo.mapper.ProductMapper;
import com.example.demo.mapper.ShoppingCartMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;@Service
public class ShoppingCartService {@Autowiredprivate ProductMapper productMapper;@Autowiredprivate ShoppingCartMapper shoppingCartMapper;@Transactionalpublic void addToCart(Long userId, Long productId, int quantity) {int updatedRows = productMapper.reduceStock(productId, quantity);if (updatedRows == 0) {throw new RuntimeException("Insufficient stock");}ShoppingCart shoppingCart = new ShoppingCart();shoppingCart.setUserId(userId);shoppingCart.setProductId(productId);shoppingCart.setQuantity(quantity);shoppingCart.setReservedTime(new Timestamp(System.currentTimeMillis()));shoppingCartMapper.insert(shoppingCart);}@Transactionalpublic void releaseExpiredReservations() {Calendar calendar = Calendar.getInstance();calendar.add(Calendar.MINUTE, -15);Timestamp expiredTime = new Timestamp(calendar.getTimeInMillis());List<ShoppingCart> expiredCarts = shoppingCartMapper.selectByReservedTimeBefore(expiredTime);for (ShoppingCart cart : expiredCarts) {try {int updatedRows = productMapper.increaseStock(cart.getProductId(), cart.getQuantity());if (updatedRows == 0) {System.err.println("Failed to increase stock for product id: " + cart.getProductId());}shoppingCartMapper.deleteById(cart.getId());} catch (Exception e) {System.err.println("Error releasing reservation for cart id: " + cart.getId() + ", error: " + e.getMessage());}}}
}

这里使用悲观锁的思想,利用mysql数据库在update,insert,delete时对应数据加上行锁的特性解决并发冲突,保证了在更新数据时,数据是最新的,且其它update,insert,delete操作被阻塞,乐观锁与悲观锁的具体参考文章“乐观锁与悲观锁的使用场景”。

5. 控制器

ShoppingCartController 保持不变:

import com.example.demo.service.ShoppingCartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ShoppingCartController {@Autowiredprivate ShoppingCartService shoppingCartService;@PostMapping("/addToCart")public String addToCart(@RequestParam Long userId, @RequestParam Long productId, @RequestParam int quantity) {try {shoppingCartService.addToCart(userId, productId, quantity);return "Product added to cart successfully";} catch (Exception e) {return e.getMessage();}}
}

6. 定时任务

ReservationExpirationTask 保持不变:

import com.example.demo.service.ShoppingCartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class ReservationExpirationTask {@Autowiredprivate ShoppingCartService shoppingCartService;@Scheduled(fixedRate = 60000) // 每分钟执行一次public void releaseExpiredReservations() {shoppingCartService.releaseExpiredReservations();}
}

7. 配置 MyBatis-Plus

application.properties 保持不变:

# 数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# MyBatis-Plus 配置
mybatis-plus.mapper-locations=classpath:mapper/*.xml
http://www.xdnf.cn/news/218107.html

相关文章:

  • 清晰易懂的跨域请求知识——拿捏
  • 前端与后端开发详解:从概念到就业技能指南
  • 解锁健康密码,开启养生新旅程
  • 空间权重矩阵
  • 体育直播源码NBA足球直播M29模板赛事直播源码
  • Linux日志系统大揭秘-系统故障排查安全审计
  • openssl_error_string() 不要依赖错误信息作为逻辑判断
  • JVM | CMS垃圾收集器详解
  • OVP UVP与UVLO对比
  • 2025年DDoS攻击防御全解析:应对超大流量的实战策略
  • Springboot使用jwt实现登录认证
  • Gitea windows服务注册,服务启动、停止、重启脚本
  • JavaScript面试问题
  • 研读论文——电子科技大学《通过专家混合实现多类型上下文感知的对话推荐系统》
  • antd-vue表单实现一个临时校验效果
  • DeepSeek+Dify之六通过API调用工作流
  • 头歌java课程实验(Java中的IO流操作)
  • python脚本下载ERA5数据详细规范和教程
  • Mysql中索引的知识
  • c#栈及其应用
  • 生物信息学常用软件InSequence,3大核心功能,简易好上手
  • PyTorch 深度学习实战(23):多任务强化学习(Multi-Task RL)之扩展
  • Redis Sentinel 和 Redis Cluster 各自的原理、优缺点及适用场景是什么?
  • pStubMsg--MemorySize0x74字节是如何分配的之rpcrt4!NdrAllocate函数分析
  • 项目三 - 任务1:采用面向对象方式求三角形面积
  • 大模型落地难题:如何用LoRA低成本微调企业私有模型?
  • 信道估计--最小均方误差(MMSE)
  • 解锁植被参数反演密码:AI 与 Python 的融合之道
  • 深入理解过拟合:机器学习中的常见陷阱
  • 软考高项(信息系统项目管理师)第 4 版全章节核心考点解析(力扬老师课程精华版)