下单逻辑学习完毕
This commit is contained in:
@@ -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("库存扣减失败,订单创建失败");
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user