摘要:本博客将介绍如何使用 Spring Boot 实现一个简单的商城秒杀系统,并通过使用 Redis 和 MySQL 来增强其性能和可靠性.
随着经济的发展和人们消费观念的转变,电子商务逐渐成为人们购物的主要方式之一.高并发是电子商务网站面临的一个重要挑战.本博客将介绍如何使用 Spring Boot 实现一个简单的商城秒杀系统,并通过使用 Redis 和 MySQL 来增强其性能和可靠性.
在开始之前,您需要准备以下工具和环境:
Redis
MySQL
MyBatis
首先,我们需要创建一个数据库来存储商品信息、订单信息和秒杀活动信息.今天这一节,我们使用 MySQL 数据库,创建一个名为 shop 的数据库,并建立三个表 goods、order 和 seckill.
表 goods 存储了所有的商品信息,包括商品编号、名称、描述、价格和库存数量等等.
CREATE TABLE +goods+ ( +id+ int(11) NOT NULL AUTO_INCREMENT COMMENT '商品ID', +name+ varchar(50) NOT NULL COMMENT '商品名称', +description+ varchar(100) NOT NULL COMMENT '商品描述', +price+ decimal(10,2) NOT NULL COMMENT '商品价格', +stock_count+ int(11) NOT NULL COMMENT '商品库存', PRIMARY KEY (+id+) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';
表 order 存储了所有的订单信息,包括订单编号、用户ID、商品ID、秒杀活动ID 和订单状态等等.
CREATE TABLE +order+ ( +id+ BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '订单ID', +user_id+ BIGINT(20) NOT NULL COMMENT '用户ID', +goods_id+ BIGINT(20) NOT NULL COMMENT '商品ID', +seckill_id+ BIGINT(20) DEFAULT NULL COMMENT '秒杀活动ID', +status+ TINYINT(4) NOT NULL COMMENT '订单状态,0-未支付,1-已支付,2-已发货,3-已收货,4-已退款,5-已完成', +create_time+ TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', +update_time+ TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (+id+), UNIQUE KEY +unique_order+ (+user_id+,+goods_id+) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
表 seckill 存储了所有的秒杀活动信息,包括秒杀活动编号、商品ID、开始时间和结束时间等等.
CREATE TABLE +seckill+ ( +id+ BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '秒杀活动ID', +goods_id+ BIGINT(20) NOT NULL COMMENT '商品ID', +start_time+ TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '开始时间', +end_time+ TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '结束时间', PRIMARY KEY (+id+) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='秒杀活动表';
此时此刻呢,我们需要创建一个 Spring Boot 项目,用于实现商城高并发秒杀案例.可以使用 Spring Initializr 来快速创建一个基本的 Spring Boot 项目.
在 Spring Boot 项目中,我们需要配置 Redis 和 MySQL 的连接信息.可以在 application.properties 文件中设置以下属性:
spring.redis.host=12⑦0.0.1 spring.redis.port=6379 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/shop?serverTimezone=Asia/ShanghaiuseSSL=falseallowPublicKeyRetrieval=true spring.datasource.username=root spring.datasource.password=123456
在这一步中,我们需要定义三个实体类分别对应数据库中的 goods、order 和 seckill 表.同时,我们需要编写相应的 DAO 接口,用于操作这些实体类.
// 商品实体类 @Data public class Goods { private Long id; private String name; private String description; private BigDecimal price; private Integer stockCount; } // 商品 DAO 接口 @Mapper public interface GoodsDao { @Select("SELECT * FROM goods WHERE id = #{id}") @Update("UPDATE goods SET stock_count = stock_count - 1 WHERE id = #{id} AND stock_count > 0") int reduceStockCount(Long id); } // 订单实体类 @Data public class Order { private Long id; private Long userId; private Long goodsId; private Long seckillId; private Byte status; private Date createTime; private Date updateTime; } // 订单 DAO 接口 @Mapper public interface OrderDao { @Select("SELECT * FROM +order+ WHERE user_id = #{userId} AND goods_id = #{goodsId}") Order getOrderByUserIdAndGoodsId(@Param("userId") Long userId, @Param("goodsId") Long goodsId); @Insert("INSERT INTO +order+ (user_id, goods_id, seckill_id, status, create_time, update_time) VALUES (#{userId}, #{goodsId}, #{seckillId}, #{status},#{createTime},#{updateTime})") int insertOrder(Order order); @Select("SELECT o.*, g.name, g.price FROM +order+ o LEFT JOIN goods g ON o.goods_id = g.id WHERE o.user_id = #{userId}") ListgetOrderListByUserId(Long userId); } // 秒杀活动实体类 @Data public class Seckill { private Long id; private Long goodsId; private Date startTime; private Date endTime; } // 秒杀活动 DAO 接口 @Mapper public interface SeckillDao { @Select("SELECT * FROM seckill WHERE id = #{id}") @Update("UPDATE seckill SET end_time = #{endTime} WHERE id = #{id}") int updateSeckillEndTime(@Param("id") Long id, @Param("endTime") Date endTime); }
在这一步中,我们需要编写 Service 层和 Controller 类,用于实现商城高并发秒杀案例的核心功能.
商品 Service 层:用于获取商品信息和减少商品库存数量.
@Service public class GoodsService { private final GoodsDao goodsDao; @Autowired public GoodsService(GoodsDao goodsDao) { this.goodsDao = goodsDao; } public Goods getGoodsById(Long id) { return goodsDao.getGoodsById(id); } public boolean reduceStockCount(Long id) { return goodsDao.reduceStockCount(id) > 0; } }
@Service public class OrderService { private final OrderDao orderDao; @Autowired public OrderService(OrderDao orderDao) { this.orderDao = orderDao; } public Order createOrder(Long userId, Long goodsId, Long seckillId) { Order order = new Order(); order.setStatus((byte) 0); order.setCreateTime(new Date()); order.setUpdateTime(new Date()); orderDao.insertOrder(order); return order; } public ListgetOrderListByUserId(Long userId) { return orderDao.getOrderListByUserId(userId); } }
@Service public class SeckillService { private final SeckillDao seckillDao; @Autowired public SeckillService(SeckillDao seckillDao) { this.seckillDao = seckillDao; } public Seckill getSeckillById(Long id) { return seckillDao.getSeckillById(id); } public boolean updateSeckillEndTime(Long id, Date endTime) { return seckillDao.updateSeckillEndTime(id, endTime) > 0; } }
@RestController @RequestMapping("/order") public class OrderController { private final OrderService orderService; @Autowired public OrderController(OrderService orderService) { this.orderService = orderService; } @PostMapping("/create") public CommonResultcreateOrder(@RequestParam("userId") Long userId, @RequestParam("goodsId") Long goodsId, @RequestParam("seckillId") Long seckillId) { Order order = orderService.createOrder(userId, goodsId, seckillId); if (order == null) { return CommonResult.failed(ResultCode.FAILURE); } return CommonResult.success(order); } @GetMapping("/list") public CommonResult > getOrderListByUserId(@RequestParam("userId") Long userId) { List
orderList = orderService.getOrderListByUserId(userId); return CommonResult.success(orderList); } }
秒杀活动 Controller:用于处理秒杀活动相关的请求.
@RestController @RequestMapping("/seckill") public class SeckillController { private final SeckillService seckillService; private final GoodsService goodsService; private final OrderService orderService; @Autowired public SeckillController(SeckillService seckillService, GoodsService goodsService, OrderService orderService) { this.seckillService = seckillService; this.goodsService = goodsService; this.orderService = orderService; } @PostMapping("/start") public CommonResult
在商城高并发秒杀案例中,一个重要的问题是如何保证商品库存数量的一致性和秒杀结果的正确性.为了解决这个问题,我们可以使用 Redis 实现分布式锁.
在 RedisService 类中实现分布式锁:
@Service public class RedisService { private final RedisTemplateredisTemplate; @Autowired public RedisService(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public boolean lock(String key, String value, long expire) { Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, Duration.ofSeconds(expire)); return result != null result; } public void unlock(String key, String value) { if (value.equals(redisTemplate.opsForValue().get(key))) { redisTemplate.delete(key); } } }
在 SeckillService 中使用分布式锁实现秒杀接口:
@Service public class SeckillService { private final RedisService redisService; private final SeckillDao seckillDao; private final GoodsDao goodsDao; private final OrderDao orderDao; @Autowired public SeckillService(RedisService redisService, SeckillDao seckillDao, GoodsDao goodsDao, OrderDao orderDao) { this.redisService = redisService; this.seckillDao = seckillDao; this.goodsDao = goodsDao; this.orderDao = orderDao; } public CommonResult
以上就是土嘎嘎小编大虾米为大家整理的相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!