道無精粗,人之所見有精粗。如這一間房,人初進來,只見一個大規模如此。處久,便柱壁之類,一一看得明白。再久,如柱上有些文藻,細細都看出來。然只是一間房。
// 搶取訂單函數
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<String> {
// 消息處理函數
@Override
@Transactional(rollbackFor = Exception.class)
public void onReceiveMessages(MetaqMessage<String> 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 List<OrderDO> queryTimeout();
}
/** 訂單服務接口 */
public interface OrderService {
/** 查詢過期訂單函數 */
public List<OrderVO> 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 List<OrderDO> queryTimeout(@Param("maxCount") Integer maxCount);
}
/** 訂單服務接口 */
public interface OrderService {
/** 查詢過期訂單函數 */
public List<OrderVO> 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 List<OrderDO> queryTimeout(@Param("startIndex") Long startIndex, @Param("pageSize") Integer pageSize);
}
/** 訂單服務接口 */
public interface OrderService {
/** 查詢過期訂單函數 */
public PageData<OrderVO> 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 List<OrderDO> queryTimeout(@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<OrderDO> 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 List<OrderDO> queryTimeout(@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<OrderDO> orderList = orderDAO.queryTimeout(PAGE_SIZE);
for (OrderDO order : orderList) {
// 進行超時關閉
......
orderDAO.setTimeoutClosed(order.getId());
}
// 檢查處理完畢
if(orderList.size() < PAGE_SIZE) {
break;
}
}
}
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。