下单逻辑学习完毕

This commit is contained in:
2026-03-03 19:39:54 +08:00
parent 8b37cccb93
commit b0c2889ddf
4 changed files with 117 additions and 53 deletions

View File

@@ -33,6 +33,17 @@ public class OrderController {
@PostMapping("/create") @PostMapping("/create")
public Result<Object> createOrder(@RequestBody Map<String, Object> jsonMap){ public Result<Object> createOrder(@RequestBody Map<String, Object> jsonMap){
Object businessIdObj = jsonMap.get("businessId");
String businessId = null;
if (businessIdObj != null) {
businessId = businessIdObj.toString().trim(); // 转字符串并去除首尾空格
}
// 2. 判断businessId是否存在核心逻辑
if (businessId == null || businessId.isEmpty()) {
// businessId不存在/为空 → 返回参数错误
return Result.fail(400, "businessId不能为空");
}
try { try {
// 1. 安全获取userId先转Number再取int值兼容Integer/Long // 1. 安全获取userId先转Number再取int值兼容Integer/Long
Number userIdNum = (Number) jsonMap.get("userId"); Number userIdNum = (Number) jsonMap.get("userId");
@@ -61,7 +72,7 @@ public class OrderController {
stockDeductDTO.setDeductNum(deductNum); stockDeductDTO.setDeductNum(deductNum);
// 5. 调用服务 // 5. 调用服务
int serviceResult = orderService.createOrder(stockDeductDTO, userId); int serviceResult = orderService.createOrder(stockDeductDTO, userId,businessId);
if (serviceResult != 0) { if (serviceResult != 0) {
// 库存扣减/订单创建失败 // 库存扣减/订单创建失败
return Result.fail("库存扣减失败,订单创建失败"); return Result.fail("库存扣减失败,订单创建失败");

View File

@@ -3,7 +3,9 @@ package cn.mayiming.Mapper;
import cn.mayiming.entity.Order; import cn.mayiming.entity.Order;
import feign.Param; import feign.Param;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
@@ -30,4 +32,50 @@ public interface OrderMapper {
"WHERE user_id = #{userId} " + "WHERE user_id = #{userId} " +
"ORDER BY create_time DESC") "ORDER BY create_time DESC")
List<Order> selectByUserId(@Param("userId") Integer userId); List<Order> selectByUserId(@Param("userId") Integer userId);
/**
* 判断businessId是否存在于订单表中
* @param businessId 业务唯一标识如幂等请求ID/外部订单号等)
* @return 存在返回true不存在返回false
*/
@Select("SELECT COUNT(1) FROM idempotent_record WHERE business_id = #{businessId}")
Integer countByBusinessId(@Param("businessId") String businessId);
/**
* 插入幂等记录核心利用唯一索引uk_request_id防重复
* @param businessId 业务唯一标识UUID
* @param status 处理状态0-处理中 1-处理成功 2-处理失败
* @return 插入成功返回1失败返回0唯一索引冲突时
*/
@Insert("INSERT INTO idempotent_record (business_id, status) " +
"VALUES (#{businessId}, #{status}) " +
"ON DUPLICATE KEY UPDATE update_time = CURRENT_TIMESTAMP")
Integer insertIdempotentRecord(@Param("businessId") String businessId,
@Param("status") Integer status);
/**
* 更新幂等记录状态(业务成功/失败后调用)
* @param businessId 业务唯一标识UUID
* @param status 处理状态1-处理成功 2-处理失败
* @return 更新成功返回1无匹配记录返回0
*/
@Update("UPDATE idempotent_record SET status = #{status}, update_time = CURRENT_TIMESTAMP " +
"WHERE business_id = #{businessId}")
Integer updateIdempotentStatus(@Param("businessId") String businessId,
@Param("status") Integer status);
/**
* 插入订单记录(核心业务操作)
* @param order 订单对象
* @return 插入成功返回1失败返回0
*/
@Insert("INSERT INTO t_order (order_no, user_id, goods_id, order_amount, order_status) " +
"VALUES (#{orderNo}, #{userId}, #{goodsId}, #{orderAmount}, #{orderStatus})")
Integer insertOrder(Order order);
// 可选:生成唯一订单号(也可在代码中生成)
default String generateOrderNo() {
// 简单生成规则:时间戳 + 6位随机数
return System.currentTimeMillis() + "" + (int)(Math.random() * 900000 + 100000);
}
} }

View File

@@ -10,7 +10,9 @@ import jakarta.annotation.Resource;
import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
@Service @Service
@@ -56,15 +58,55 @@ public class OrderService {
} }
} }
public int createOrder(StockDeductDTO stockDeductDTO,int i) { @Transactional(rollbackFor = Exception.class)
int res = 0; public int createOrder(StockDeductDTO stockDeductDTO,int userId,String businessId) {
if(stockFeignClient.deductstock(stockDeductDTO)==0){ Integer count = orderMapper.countByBusinessId(businessId);
res ++; if (count != null && count > 0) {
return 1; // 已存在,直接返回失败
} }
if(userFeignClient.GetUserByid(i)==null){ // 1.2 校验用户是否存在(远程只读,无事务管控)
res ++; if (userFeignClient.GetUserByid(userId) == null) {
return 1; // 用户不存在,直接返回失败
} }
return res;
try {
// 步骤1调用库存服务扣减库存远程操作需库存服务自身保证事务
int stockResult = stockFeignClient.deductstock(stockDeductDTO);
if (stockResult == 0) { // 假设返回0是失败非0是成功按你原有逻辑
throw new RuntimeException("库存扣减失败,返回码:" + stockResult);
}
// 步骤2构建订单对象适配t_order表
Order order = new Order();
order.setOrderNo(orderMapper.generateOrderNo()); // 生成唯一订单号
order.setUserId(Long.valueOf(userId)); // 转换为Long适配表结构
order.setGoodsId(stockDeductDTO.getId()); // 商品ID从库存DTO获取
order.setOrderAmount(new BigDecimal("99.99")); // 订单金额(实际需从商品服务获取)
order.setOrderStatus(0); // 0-待支付
// 步骤3插入订单记录核心事务管控
Integer orderInsertResult = orderMapper.insertOrder(order);
if (orderInsertResult == null || orderInsertResult == 0) {
throw new RuntimeException("订单插入失败");
}
// 步骤4插入幂等记录占坑事务管控
Integer idempotentInsertResult = orderMapper.insertIdempotentRecord(businessId, 1); // 直接标记为成功
if (idempotentInsertResult == null || idempotentInsertResult == 0) {
throw new RuntimeException("幂等记录插入失败");
}
// 所有操作成功返回0
return 0;
} catch (Exception e) {
// 任何异常触发事务回滚:订单插入、幂等插入都会回滚
e.printStackTrace();
// 可选:幂等记录标记为失败(方便排查)
orderMapper.updateIdempotentStatus(businessId, 2);
return 1;
}
} }
} }

View File

@@ -5,50 +5,13 @@ import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
@Data // Lombok 注解自动生成get/set/toString @Data
public class Order { public class Order {
/** 订单ID */ private Long id; // 主键ID
private Long id; private String orderNo; // 订单号(唯一)
/** 订单编号 */ private Long userId; // 用户ID
private String orderNo; private Long goodsId; // 商品ID对应库存扣减的stockId
/** 关联用户ID */ private BigDecimal orderAmount; // 订单金额
private Integer userId; private Integer orderStatus; // 订单状态0-待支付 1-已支付 2-已取消
/** 商品名称 */ private Date createTime; // 创建时间
private String productName;
/** 商品单价 */
private BigDecimal productPrice;
/** 购买数量 */
private Integer count;
/** 订单总金额 */
private BigDecimal totalAmount;
/** 订单状态0-待支付 1-已支付 2-已取消 3-已完成 */
private Integer status;
/** 创建时间 */
private Date createTime;
/** 更新时间 */
private Date updateTime;
// 可选:添加状态枚举,避免硬编码数字
public enum OrderStatus {
PENDING_PAYMENT(0, "待支付"),
PAID(1, "已支付"),
CANCELLED(2, "已取消"),
COMPLETED(3, "已完成");
private final int code;
private final String desc;
OrderStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
} }