道无精粗,人之所见有精粗。如这一间房,人初进来,只见一个大规模如此。处久,便柱壁之类,一一看得明白。再久,如柱上有些文藻,细细都看出来。然只是一间房。
// 抢取订单函数 public synchronized void grabOrder(Long orderId, Long userId) { // 获取订单信息 OrderDO order = orderDAO.get(orderId); if (Objects.isNull(order)) { throw new BizRuntimeException(String.format("订单(%s)不存在", orderId)); } // 检查订单状态 if (!Objects.equals(order.getStatus, OrderStatus.WAITING_TO_GRAB.getValue())) { throw new BizRuntimeException(String.format("订单(%s)已被抢", orderId)); } // 设置订单被抢 orderDAO.setGrabed(orderId, userId); }
// 抢取订单函数 public void grabOrder(Long orderId, Long userId) { Long lockId = orderDistributedLock.lock(orderId); try { grabOrderWithoutLock(orderId, userId); } finally { orderDistributedLock.unlock(orderId, lockId); } } // 不带锁的抢取订单函数 private void grabOrderWithoutLock(Long orderId, Long userId) { // 获取订单信息 OrderDO order = orderDAO.get(orderId); if (Objects.isNull(order)) { throw new BizRuntimeException(String.format("订单(%s)不存在", orderId)); } // 检查订单状态 if (!Objects.equals(order.getStatus, OrderStatus.WAITING_TO_GRAB.getValue())) { throw new BizRuntimeException(String.format("订单(%s)已被抢", orderId)); } // 设置订单被抢 orderDAO.setGrabed(orderId, userId); }
// 登录函数(示意写法) public UserVO login(String phoneNumber, String verifyCode) { // 检查验证码 if (!checkVerifyCode(phoneNumber, verifyCode)) { throw new ExampleException("验证码错误"); } // 检查用户存在 UserDO user = userDAO.getByPhoneNumber(phoneNumber); if (Objects.nonNull(user)) { return transUser(user); } // 创建新用户 return createNewUser(user); } // 创建新用户函数 private UserVO createNewUser(String phoneNumber) { // 创建新用户 UserDO user = new UserDO(); ... userDAO.insert(user); // 绑定优惠券 couponService.bindCoupon(user.getId(), CouponType.NEW_USER); // 返回新用户 return transUser(user); }
// 创建新用户函数 private UserVO createNewUser(String phoneNumber) { // 创建新用户 UserDO user = new UserDO(); ... userDAO.insert(user); // 绑定优惠券 executorService.execute(()->couponService.bindCoupon(user.getId(), CouponType.NEW_USER)); // 返回新用户 return transUser(user); }
// 创建新用户函数 private UserVO createNewUser(String phoneNumber) { // 创建新用户 UserDO user = new UserDO(); ... userDAO.insert(user); // 发送优惠券消息 Long userId = user.getId(); CouponMessageDataVO data = new CouponMessageDataVO(); data.setUserId(userId); data.setCouponType(CouponType.NEW_USER); Message message = new Message(TOPIC, TAG, userId, JSON.toJSONBytes(data)); SendResult result = metaqTemplate.sendMessage(message); if (!Objects.equals(result, SendStatus.SEND_OK)) { log.error("发送用户({})绑定优惠券消息失败:{}", userId, JSON.toJSONString(result)); } // 返回新用户 return transUser(user); }
// 优惠券服务类 @Slf4j @Service public class CouponService extends DefaultMessageListener{ // 消息处理函数 @Override @Transactional(rollbackFor = Exception.class) public void onReceiveMessages(MetaqMessage message) { // 获取消息体 String body = message.getBody(); if (StringUtils.isBlank(body)) { log.warn("获取消息({})体为空", message.getId()); return; } // 解析消息数据 CouponMessageDataVO data = JSON.parseObject(body, CouponMessageDataVO.class); if (Objects.isNull(data)) { log.warn("解析消息({})体为空", message.getId()); return; } // 绑定优惠券 bindCoupon(data.getUserId(), data.getCouponType()); } }
/** 完成采购动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void finishPurchase(PurchaseOrder order) { // 完成相关处理 ...... // 回流采购单(调用HTTP接口) backflowPurchaseOrder(order); // 设置完成状态 purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.FINISHED.getValue()); }
/** 完成采购动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void finishPurchase(PurchaseOrder order) { // 完成相关处理 ...... // 设置完成状态 purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.FINISHED.getValue()); } /** 执行回流动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void executeBackflow(PurchaseOrder order) { // 回流采购单(调用HTTP接口) backflowPurchaseOrder(order); // 设置回流状态 purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.BACKFLOWED.getValue()); }
/** 执行回流动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void executeBackflow(PurchaseOrder order) { // 完成原始采购单 rawPurchaseOrderDAO.setStatus(order.getRawId(), RawPurchaseOrderStatus.FINISHED.getValue()); // 设置回流状态 purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.BACKFLOWED.getValue()); }
/** 采购单服务接口 */ public interface PurchaseOrderService { /** 完成采购单函数 */ public void finishPurchaseOrder(Long orderId); } /** 采购单服务实现 */ @Service("purchaseOrderService") public class PurchaseOrderServiceImpl implements PurchaseOrderService { /** 完成采购单函数 */ @Override @Transactional(rollbackFor = Exception.class) public void finishPurchaseOrder(Long orderId) { // 相关处理 ... // 完成采购单 purchaseOrderService.finishPurchaseOrder(order.getRawId()); } }
/** 执行回流动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void executeBackflow(PurchaseOrder order) { // 完成采购单 purchaseOrderService.finishPurchaseOrder(order.getRawId()); // 设置回流状态 purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.BACKFLOWED.getValue()); }
/** 订单DAO接口 */ public interface OrderDAO { /** 查询过期订单函数 */ @Select("select * from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day)") public ListqueryTimeout(); } /** 订单服务接口 */ public interface OrderService { /** 查询过期订单函数 */ public List queryTimeout(); }
/** 订单DAO接口 */ public interface OrderDAO { /** 查询过期订单函数 */ @Select("select * from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day) limit 0, #{maxCount}") public ListqueryTimeout(@Param("maxCount") Integer maxCount); } /** 订单服务接口 */ public interface OrderService { /** 查询过期订单函数 */ public List queryTimeout(Integer maxCount); }
/** 订单DAO接口 */ public interface OrderDAO { /** 统计过期订单函数 */ @Select("select count(*) from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day)") public Long countTimeout(); /** 查询过期订单函数 */ @Select("select * from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day) limit #{startIndex}, #{pageSize}") public ListqueryTimeout(@Param("startIndex") Long startIndex, @Param("pageSize") Integer pageSize); } /** 订单服务接口 */ public interface OrderService { /** 查询过期订单函数 */ public PageData queryTimeout(Long startIndex, Integer pageSize); }
/** 订单DAO接口 */ public interface OrderDAO { /** 查询过期订单函数 */ @Select("select * from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day) limit #{startIndex}, #{pageSize}") public ListqueryTimeout(@Param("startIndex") Long startIndex, @Param("pageSize") Integer pageSize); /** 设置订单超时关闭 */ @Update("update t_order set status = 10 where id = #{orderId} and status = 5") public Long setTimeoutClosed(@Param("orderId") Long orderId) } /** 关闭过期订单作业类 */ public class CloseTimeoutOrderJob extends Job { /** 分页数量 */ private static final int PAGE_COUNT = 100; /** 分页大小 */ private static final int PAGE_SIZE = 1000; /** 作业执行函数 */ @Override public void execute() { for (int i = 0; i < PAGE_COUNT; i++) { // 查询处理订单 List orderList = orderDAO.queryTimeout(i * PAGE_COUNT, PAGE_SIZE); for (OrderDO order : orderList) { // 进行超时关闭 ...... orderDAO.setTimeoutClosed(order.getId()); } // 检查处理完毕 if(orderList.size() < PAGE_SIZE) { break; } } } }
当满足查询条件的数据,在操作中不再满足查询条件时,会导致后续分页查询中前startIndex(开始序号)条满足条件的数据被跳过。
/** 订单DAO接口 */ public interface OrderDAO { /** 查询过期订单函数 */ @Select("select * from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day) limit 0, #{maxCount}") public ListqueryTimeout(@Param("maxCount") Integer maxCount); /** 设置订单超时关闭 */ @Update("update t_order set status = 10 where id = #{orderId} and status = 5") public Long setTimeoutClosed(@Param("orderId") Long orderId) } /** 关闭过期订单作业(定时作业) */ public class CloseTimeoutOrderJob extends Job { /** 分页数量 */ private static final int PAGE_COUNT = 100; /** 分页大小 */ private static final int PAGE_SIZE = 1000; /** 作业执行函数 */ @Override public void execute() { for (int i = 0; i < PAGE_COUNT; i++) { // 查询处理订单 List orderList = orderDAO.queryTimeout(PAGE_SIZE); for (OrderDO order : orderList) { // 进行超时关闭 ...... orderDAO.setTimeoutClosed(order.getId()); } // 检查处理完毕 if(orderList.size() < PAGE_SIZE) { break; } } } }