下单逻辑学习完毕
This commit is contained in:
@@ -33,6 +33,17 @@ public class OrderController {
|
||||
|
||||
@PostMapping("/create")
|
||||
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 {
|
||||
// 1. 安全获取userId:先转Number,再取int值(兼容Integer/Long)
|
||||
Number userIdNum = (Number) jsonMap.get("userId");
|
||||
@@ -61,7 +72,7 @@ public class OrderController {
|
||||
stockDeductDTO.setDeductNum(deductNum);
|
||||
|
||||
// 5. 调用服务
|
||||
int serviceResult = orderService.createOrder(stockDeductDTO, userId);
|
||||
int serviceResult = orderService.createOrder(stockDeductDTO, userId,businessId);
|
||||
if (serviceResult != 0) {
|
||||
// 库存扣减/订单创建失败
|
||||
return Result.fail("库存扣减失败,订单创建失败");
|
||||
|
||||
@@ -3,7 +3,9 @@ package cn.mayiming.Mapper;
|
||||
|
||||
import cn.mayiming.entity.Order;
|
||||
import feign.Param;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@@ -30,4 +32,50 @@ public interface OrderMapper {
|
||||
"WHERE user_id = #{userId} " +
|
||||
"ORDER BY create_time DESC")
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ import jakarta.annotation.Resource;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@@ -56,15 +58,55 @@ public class OrderService {
|
||||
}
|
||||
}
|
||||
|
||||
public int createOrder(StockDeductDTO stockDeductDTO,int i) {
|
||||
int res = 0;
|
||||
if(stockFeignClient.deductstock(stockDeductDTO)==0){
|
||||
res ++;
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int createOrder(StockDeductDTO stockDeductDTO,int userId,String businessId) {
|
||||
Integer count = orderMapper.countByBusinessId(businessId);
|
||||
if (count != null && count > 0) {
|
||||
return 1; // 已存在,直接返回失败
|
||||
}
|
||||
if(userFeignClient.GetUserByid(i)==null){
|
||||
res ++;
|
||||
// 1.2 校验用户是否存在(远程只读,无事务管控)
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,50 +5,13 @@ import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data // Lombok 注解,自动生成get/set/toString
|
||||
@Data
|
||||
public class Order {
|
||||
/** 订单ID */
|
||||
private Long id;
|
||||
/** 订单编号 */
|
||||
private String orderNo;
|
||||
/** 关联用户ID */
|
||||
private Integer userId;
|
||||
/** 商品名称 */
|
||||
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;
|
||||
}
|
||||
}
|
||||
private Long id; // 主键ID
|
||||
private String orderNo; // 订单号(唯一)
|
||||
private Long userId; // 用户ID
|
||||
private Long goodsId; // 商品ID(对应库存扣减的stockId)
|
||||
private BigDecimal orderAmount; // 订单金额
|
||||
private Integer orderStatus; // 订单状态:0-待支付 1-已支付 2-已取消
|
||||
private Date createTime; // 创建时间
|
||||
}
|
||||
Reference in New Issue
Block a user