最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springboot+redis實現(xiàn)訂單過期(超時取消)功能的方法詳解

 更新時間:2025年12月12日 14:34:21   作者:IT界Tony哥  
在Spring Boot中使用Redis實現(xiàn)訂單過期(超時取消)功能,有多種成熟方案,本文為大家整理了幾個詳細方法,文中的示例代碼講解詳細,大家可以根據(jù)需要進行選擇

在Spring Boot中使用Redis實現(xiàn)訂單過期(超時取消)功能,有多種成熟方案。以下是完整的實現(xiàn)方案:

一、Redis鍵過期回調(diào)方案(推薦)

1. 配置Redis監(jiān)聽器

@Configuration
public class RedisKeyExpirationConfig {
    
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(
            RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}

2. 監(jiān)聽鍵過期事件

@Component
@Slf4j
public class OrderExpirationListener {
    
    private static final String ORDER_KEY_PREFIX = "order:";
    private static final String ORDER_EXPIRE_KEY_PREFIX = "order:expire:";
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private OrderService orderService;
    
    /**
     * 監(jiān)聽所有鍵過期事件
     */
    @EventListener
    public void handleKeyExpiredEvent(KeyExpiredEvent<String> event) {
        String expiredKey = new String(event.getSource());
        
        if (expiredKey.startsWith(ORDER_EXPIRE_KEY_PREFIX)) {
            String orderId = expiredKey.substring(ORDER_EXPIRE_KEY_PREFIX.length());
            handleOrderExpired(orderId);
        }
    }
    
    private void handleOrderExpired(String orderId) {
        log.info("檢測到訂單過期: {}", orderId);
        
        try {
            // 異步處理,避免阻塞Redis監(jiān)聽線程
            CompletableFuture.runAsync(() -> {
                boolean result = orderService.cancelExpiredOrder(orderId);
                if (result) {
                    log.info("訂單 {} 已成功取消", orderId);
                } else {
                    log.warn("訂單 {} 取消失敗或已處理", orderId);
                }
            });
        } catch (Exception e) {
            log.error("處理訂單過期異常: {}", orderId, e);
        }
    }
}

3. Redis配置(開啟鍵空間通知)

在Redis配置文件redis.conf中開啟鍵空間通知:

# 開啟鍵空間通知
notify-keyspace-events Ex

# 或者開啟所有事件
# notify-keyspace-events AKE

Spring Boot配置:

spring:
  redis:
    host: localhost
    port: 6379
    database: 0
    # 監(jiān)聽鍵過期事件
    listen-patterns: "__keyevent@*__:expired"

二、延時隊列方案(Redisson實現(xiàn))

1. 添加Redisson依賴

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.5</version>
</dependency>

2. 使用Redisson延時隊列

@Service
@Slf4j
public class OrderDelayQueueService {
    
    @Autowired
    private RedissonClient redissonClient;
    
    @Autowired
    private OrderService orderService;
    
    private static final String DELAY_QUEUE_NAME = "order:delay:queue";
    private static final String PROCESSING_SET = "order:delay:processing";
    
    /**
     * 添加訂單到延時隊列
     * @param orderId 訂單ID
     * @param delayTime 延時時間(分鐘)
     */
    public void addToDelayQueue(String orderId, long delayTime) {
        RBlockingQueue<String> blockingQueue = redissonClient
            .getBlockingQueue(DELAY_QUEUE_NAME);
        RDelayedQueue<String> delayedQueue = redissonClient
            .getDelayedQueue(blockingQueue);
        
        // 添加到延時隊列
        delayedQueue.offer(orderId, delayTime, TimeUnit.MINUTES);
        
        log.info("訂單 {} 已添加到延時隊列,將在 {} 分鐘后過期", orderId, delayTime);
    }
    
    /**
     * 啟動延時隊列消費者
     */
    @PostConstruct
    public void startDelayQueueConsumer() {
        new Thread(this::consumeDelayQueue, "delay-queue-consumer").start();
    }
    
    private void consumeDelayQueue() {
        RBlockingQueue<String> blockingQueue = redissonClient
            .getBlockingQueue(DELAY_QUEUE_NAME);
        
        while (true) {
            try {
                // 從隊列中取出過期的訂單
                String orderId = blockingQueue.take();
                
                // 處理訂單過期
                processExpiredOrder(orderId);
                
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("延時隊列消費線程被中斷", e);
                break;
            } catch (Exception e) {
                log.error("處理延時隊列消息異常", e);
            }
        }
    }
    
    /**
     * 處理過期訂單
     */
    private void processExpiredOrder(String orderId) {
        RSet<String> processingSet = redissonClient.getSet(PROCESSING_SET);
        
        // 使用set防止重復處理
        if (processingSet.add(orderId)) {
            try {
                boolean result = orderService.cancelExpiredOrder(orderId);
                if (result) {
                    log.info("延時隊列:訂單 {} 已過期取消", orderId);
                } else {
                    log.info("延時隊列:訂單 {} 無需處理", orderId);
                }
            } finally {
                processingSet.remove(orderId);
            }
        }
    }
}

三、ZSet有序集合方案

@Service
@Slf4j
public class OrderExpireZSetService {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private static final String ORDER_EXPIRE_ZSET = "order:expire:zset";
    private static final String ORDER_PROCESSING_SET = "order:processing:set";
    
    /**
     * 添加訂單到過期集合
     * @param orderId 訂單ID
     * @param expireTime 過期時間戳
     */
    public void addOrderToExpireSet(String orderId, long expireTime) {
        redisTemplate.opsForZSet().add(ORDER_EXPIRE_ZSET, orderId, expireTime);
        log.info("訂單 {} 已添加到過期集合,過期時間: {}", orderId, 
                 new Date(expireTime));
    }
    
    /**
     * 批量掃描過期訂單
     */
    public void scanExpiredOrders() {
        long now = System.currentTimeMillis();
        
        // 獲取已過期的訂單
        Set<String> expiredOrders = redisTemplate.opsForZSet()
            .rangeByScore(ORDER_EXPIRE_ZSET, 0, now);
        
        if (expiredOrders != null && !expiredOrders.isEmpty()) {
            for (String orderId : expiredOrders) {
                processExpiredOrder(orderId);
            }
            
            // 移除已處理的訂單
            redisTemplate.opsForZSet().removeRangeByScore(
                ORDER_EXPIRE_ZSET, 0, now);
        }
    }
    
    /**
     * 定時掃描任務
     */
    @Scheduled(fixedDelay = 30000) // 每30秒執(zhí)行一次
    public void scheduledScan() {
        log.debug("開始掃描過期訂單");
        scanExpiredOrders();
    }
    
    private void processExpiredOrder(String orderId) {
        // 使用setnx防止重復處理
        Boolean success = redisTemplate.opsForValue()
            .setIfAbsent(ORDER_PROCESSING_SET + ":" + orderId, "1", 5, TimeUnit.MINUTES);
        
        if (Boolean.TRUE.equals(success)) {
            try {
                // 處理訂單過期邏輯
                handleOrderExpired(orderId);
            } finally {
                // 清理處理標記
                redisTemplate.delete(ORDER_PROCESSING_SET + ":" + orderId);
            }
        }
    }
    
    private void handleOrderExpired(String orderId) {
        // TODO: 實現(xiàn)訂單過期處理邏輯
        log.info("處理過期訂單: {}", orderId);
    }
}

四、完整訂單服務實現(xiàn)

1. 訂單狀態(tài)枚舉

public enum OrderStatus {
    
    PENDING_PAYMENT(0, "待支付"),
    PAID(1, "已支付"),
    COMPLETED(2, "已完成"),
    CANCELLED(3, "已取消"),
    EXPIRED(4, "已過期");
    
    private final int code;
    private final String description;
    
    OrderStatus(int code, String description) {
        this.code = code;
        this.description = description;
    }
    
    // getter方法省略
}

2. 訂單實體

@Data
@Entity
@Table(name = "t_order")
public class Order {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true)
    private String orderNo;
    
    private Long userId;
    private BigDecimal amount;
    
    @Enumerated(EnumType.ORDINAL)
    private OrderStatus status = OrderStatus.PENDING_PAYMENT;
    
    @Column(name = "expire_time")
    private LocalDateTime expireTime;
    
    @Column(name = "create_time")
    private LocalDateTime createTime = LocalDateTime.now();
    
    @Column(name = "update_time")
    private LocalDateTime updateTime = LocalDateTime.now();
    
    /**
     * 判斷訂單是否已過期
     */
    public boolean isExpired() {
        return LocalDateTime.now().isAfter(expireTime) 
            && status == OrderStatus.PENDING_PAYMENT;
    }
}

3. 訂單服務實現(xiàn)

@Service
@Slf4j
@Transactional
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Autowired
    private OrderDelayQueueService delayQueueService;
    
    @Autowired
    private OrderExpireZSetService zSetService;
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    private static final String ORDER_LOCK_PREFIX = "order:lock:";
    private static final String ORDER_EXPIRE_KEY_PREFIX = "order:expire:";
    private static final int ORDER_EXPIRE_MINUTES = 30; // 30分鐘未支付過期
    
    /**
     * 創(chuàng)建訂單
     */
    public Order createOrder(Long userId, BigDecimal amount) {
        Order order = new Order();
        order.setOrderNo(generateOrderNo());
        order.setUserId(userId);
        order.setAmount(amount);
        order.setStatus(OrderStatus.PENDING_PAYMENT);
        order.setExpireTime(LocalDateTime.now().plusMinutes(ORDER_EXPIRE_MINUTES));
        
        order = orderRepository.save(order);
        
        // 設置Redis過期
        setOrderExpire(order.getOrderNo());
        
        // 添加到延時隊列
        delayQueueService.addToDelayQueue(order.getOrderNo(), ORDER_EXPIRE_MINUTES);
        
        // 添加到ZSet
        zSetService.addOrderToExpireSet(
            order.getOrderNo(), 
            order.getExpireTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
        );
        
        log.info("創(chuàng)建訂單成功: {}, 過期時間: {}", order.getOrderNo(), order.getExpireTime());
        return order;
    }
    
    /**
     * 設置Redis鍵過期
     */
    private void setOrderExpire(String orderNo) {
        String key = ORDER_EXPIRE_KEY_PREFIX + orderNo;
        String value = String.valueOf(System.currentTimeMillis());
        
        // 設置30分鐘后過期
        redisTemplate.opsForValue().set(
            key, 
            value, 
            ORDER_EXPIRE_MINUTES, 
            TimeUnit.MINUTES
        );
        
        // 同時存儲訂單信息,用于過期時處理
        Map<String, String> orderInfo = new HashMap<>();
        orderInfo.put("orderNo", orderNo);
        orderInfo.put("userId", "1"); // 實際從訂單獲取
        orderInfo.put("amount", "100.00");
        
        redisTemplate.opsForHash().putAll(ORDER_KEY_PREFIX + orderNo, orderInfo);
    }
    
    /**
     * 支付成功處理
     */
    public boolean processPayment(String orderNo) {
        // 獲取分布式鎖
        String lockKey = ORDER_LOCK_PREFIX + orderNo;
        Boolean locked = redisTemplate.opsForValue()
            .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
        
        if (Boolean.FALSE.equals(locked)) {
            throw new RuntimeException("訂單處理中,請稍后");
        }
        
        try {
            Order order = orderRepository.findByOrderNo(orderNo)
                .orElseThrow(() -> new RuntimeException("訂單不存在"));
            
            // 檢查訂單狀態(tài)
            if (order.getStatus() != OrderStatus.PENDING_PAYMENT) {
                throw new RuntimeException("訂單狀態(tài)異常: " + order.getStatus());
            }
            
            // 檢查是否過期
            if (order.isExpired()) {
                order.setStatus(OrderStatus.EXPIRED);
                orderRepository.save(order);
                throw new RuntimeException("訂單已過期");
            }
            
            // 更新訂單狀態(tài)
            order.setStatus(OrderStatus.PAID);
            order.setUpdateTime(LocalDateTime.now());
            orderRepository.save(order);
            
            // 移除過期設置
            removeOrderExpire(orderNo);
            
            // 發(fā)布支付成功事件
            eventPublisher.publishEvent(new OrderPaidEvent(this, order));
            
            log.info("訂單支付成功: {}", orderNo);
            return true;
            
        } finally {
            // 釋放鎖
            redisTemplate.delete(lockKey);
        }
    }
    
    /**
     * 處理過期訂單
     */
    public boolean cancelExpiredOrder(String orderNo) {
        String lockKey = ORDER_LOCK_PREFIX + orderNo;
        Boolean locked = redisTemplate.opsForValue()
            .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
        
        if (Boolean.FALSE.equals(locked)) {
            return false;
        }
        
        try {
            Order order = orderRepository.findByOrderNo(orderNo)
                .orElseThrow(() -> new RuntimeException("訂單不存在"));
            
            // 雙重檢查:訂單是否仍為待支付狀態(tài)
            if (order.getStatus() != OrderStatus.PENDING_PAYMENT) {
                log.info("訂單 {} 狀態(tài)已變更為 {},跳過取消", orderNo, order.getStatus());
                return false;
            }
            
            // 檢查是否真的過期
            if (!order.isExpired()) {
                log.info("訂單 {} 未過期,跳過取消", orderNo);
                return false;
            }
            
            // 更新訂單狀態(tài)
            order.setStatus(OrderStatus.EXPIRED);
            order.setUpdateTime(LocalDateTime.now());
            orderRepository.save(order);
            
            // 釋放庫存等業(yè)務邏輯
            releaseStock(order);
            
            // 發(fā)送通知
            sendExpireNotification(order);
            
            log.info("訂單 {} 已過期取消", orderNo);
            return true;
            
        } finally {
            redisTemplate.delete(lockKey);
        }
    }
    
    /**
     * 移除訂單過期設置
     */
    private void removeOrderExpire(String orderNo) {
        // 刪除過期key
        redisTemplate.delete(ORDER_EXPIRE_KEY_PREFIX + orderNo);
        
        // 從延時隊列移除
        // 注意:Redisson延時隊列不支持直接移除,需要其他方式
        
        // 從ZSet移除
        redisTemplate.opsForZSet().remove(ORDER_EXPIRE_ZSET, orderNo);
        
        // 刪除訂單緩存
        redisTemplate.delete(ORDER_KEY_PREFIX + orderNo);
    }
    
    /**
     * 生成訂單號
     */
    private String generateOrderNo() {
        // 時間戳 + 隨機數(shù)
        return "ORD" + 
               System.currentTimeMillis() + 
               String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
    }
    
    private void releaseStock(Order order) {
        // 釋放庫存邏輯
        log.info("釋放訂單 {} 的庫存", order.getOrderNo());
    }
    
    private void sendExpireNotification(Order order) {
        // 發(fā)送通知邏輯
        log.info("發(fā)送訂單 {} 過期通知", order.getOrderNo());
    }
}

4. 訂單支付事件

public class OrderPaidEvent extends ApplicationEvent {
    
    private final Order order;
    
    public OrderPaidEvent(Object source, Order order) {
        super(source);
        this.order = order;
    }
    
    public Order getOrder() {
        return order;
    }
}

五、多級過期策略(增強版)

@Component
@Slf4j
public class OrderExpireManager {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private static final String ORDER_EXPIRE_ZSET = "order:expire:zset";
    private static final String ORDER_EXPIRE_DELAY_QUEUE = "order:expire:delay:queue";
    
    /**
     * 三級過期檢測策略
     */
    public void startExpireMonitor() {
        // 1. Redis鍵過期事件(實時)
        // 2. 定時任務掃描(兜底)
        // 3. 延時隊列(精確控制)
        
        new Thread(this::monitorDelayQueue, "order-expire-monitor").start();
        new Thread(this::scheduledScan, "order-expire-scanner").start();
    }
    
    /**
     * 監(jiān)控延時隊列
     */
    private void monitorDelayQueue() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                // 從延時隊列獲取訂單
                String orderId = redisTemplate.opsForList()
                    .rightPop(ORDER_EXPIRE_DELAY_QUEUE, 1, TimeUnit.SECONDS);
                
                if (orderId != null) {
                    processExpiredOrder(orderId);
                }
            } catch (Exception e) {
                log.error("監(jiān)控延時隊列異常", e);
            }
        }
    }
    
    /**
     * 定時掃描
     */
    private void scheduledScan() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                scanExpiredOrders();
                Thread.sleep(30000); // 30秒掃描一次
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            } catch (Exception e) {
                log.error("定時掃描異常", e);
            }
        }
    }
    
    /**
     * 掃描過期訂單
     */
    private void scanExpiredOrders() {
        long now = System.currentTimeMillis();
        Set<String> expiredOrders = redisTemplate.opsForZSet()
            .rangeByScore(ORDER_EXPIRE_ZSET, 0, now);
        
        if (expiredOrders != null) {
            for (String orderId : expiredOrders) {
                processExpiredOrder(orderId);
            }
            
            // 移除已處理的訂單
            redisTemplate.opsForZSet().removeRangeByScore(
                ORDER_EXPIRE_ZSET, 0, now);
        }
    }
    
    /**
     * 處理過期訂單
     */
    private void processExpiredOrder(String orderId) {
        // 防重處理
        String lockKey = "order:expire:process:" + orderId;
        Boolean locked = redisTemplate.opsForValue()
            .setIfAbsent(lockKey, "1", 5, TimeUnit.MINUTES);
        
        if (Boolean.TRUE.equals(locked)) {
            try {
                boolean result = orderService.cancelExpiredOrder(orderId);
                if (result) {
                    log.info("成功處理過期訂單: {}", orderId);
                }
            } finally {
                redisTemplate.delete(lockKey);
            }
        }
    }
}

六、配置類

@Configuration
@EnableScheduling
public class OrderExpireConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 設置key和value的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        template.afterPropertiesSet();
        return template;
    }
    
    @Bean
    public OrderExpireManager orderExpireManager() {
        return new OrderExpireManager();
    }
    
    @PostConstruct
    public void init() {
        // 啟動過期監(jiān)控
        orderExpireManager().startExpireMonitor();
    }
}

七、API接口

@RestController
@RequestMapping("/api/orders")
@Slf4j
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @PostMapping("/create")
    public ApiResponse<Order> createOrder(@RequestBody CreateOrderRequest request) {
        Order order = orderService.createOrder(
            request.getUserId(), 
            request.getAmount()
        );
        return ApiResponse.success(order);
    }
    
    @PostMapping("/{orderNo}/pay")
    public ApiResponse<Void> payOrder(@PathVariable String orderNo) {
        boolean success = orderService.processPayment(orderNo);
        if (success) {
            return ApiResponse.success("支付成功");
        } else {
            return ApiResponse.error("支付失敗");
        }
    }
    
    @GetMapping("/{orderNo}/status")
    public ApiResponse<OrderStatus> getOrderStatus(@PathVariable String orderNo) {
        // 從Redis或數(shù)據(jù)庫獲取訂單狀態(tài)
        return ApiResponse.success(OrderStatus.PENDING_PAYMENT);
    }
}

八、測試類

@SpringBootTest
@Slf4j
class OrderExpireTest {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Test
    void testOrderExpire() throws InterruptedException {
        // 創(chuàng)建訂單
        Order order = orderService.createOrder(1L, new BigDecimal("100.00"));
        
        // 驗證Redis中已設置過期
        String expireKey = "order:expire:" + order.getOrderNo();
        String value = redisTemplate.opsForValue().get(expireKey);
        assertNotNull(value);
        
        // 驗證訂單狀態(tài)
        assertEquals(OrderStatus.PENDING_PAYMENT, order.getStatus());
        
        // 等待訂單過期
        Thread.sleep(2000); // 實際應該等30分鐘
        
        // 測試支付
        boolean paid = orderService.processPayment(order.getOrderNo());
        assertTrue(paid);
    }
    
    @Test
    void testConcurrentPay() throws InterruptedException {
        Order order = orderService.createOrder(2L, new BigDecimal("200.00"));
        
        ExecutorService executor = Executors.newFixedThreadPool(5);
        CountDownLatch latch = new CountDownLatch(5);
        
        AtomicInteger successCount = new AtomicInteger(0);
        
        for (int i = 0; i < 5; i++) {
            executor.submit(() -> {
                try {
                    boolean result = orderService.processPayment(order.getOrderNo());
                    if (result) {
                        successCount.incrementAndGet();
                    }
                } catch (Exception e) {
                    log.error("支付異常", e);
                } finally {
                    latch.countDown();
                }
            });
        }
        
        latch.await();
        executor.shutdown();
        
        // 只有一個支付成功
        assertEquals(1, successCount.get());
    }
}

九、監(jiān)控和告警

@Component
@Slf4j
public class OrderExpireMonitor {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Scheduled(fixedRate = 60000) // 每分鐘執(zhí)行一次
    public void monitorExpireOrders() {
        String expireKeyPattern = "order:expire:*";
        
        // 統(tǒng)計待過期訂單數(shù)量
        Set<String> keys = redisTemplate.keys(expireKeyPattern);
        long expireCount = keys != null ? keys.size() : 0;
        
        // 統(tǒng)計即將在5分鐘內(nèi)過期的訂單
        long soonExpireCount = keys.stream()
            .map(key -> redisTemplate.getExpire(key, TimeUnit.SECONDS))
            .filter(ttl -> ttl != null && ttl > 0 && ttl <= 300)
            .count();
        
        // 記錄監(jiān)控日志
        log.info("訂單過期監(jiān)控 - 待過期訂單: {}, 即將過期訂單: {}", 
                 expireCount, soonExpireCount);
        
        // 發(fā)送告警
        if (soonExpireCount > 100) {
            sendAlert("大量訂單即將過期: " + soonExpireCount + " 個");
        }
    }
    
    private void sendAlert(String message) {
        // 發(fā)送告警到監(jiān)控系統(tǒng)
        log.warn("訂單過期告警: {}", message);
    }
}

總結(jié)建議

推薦方案

生產(chǎn)環(huán)境推薦組合方案

  • 主方案:Redisson延時隊列? + Redis鍵過期回調(diào)
  • 兜底方案:定時任務掃描ZSet
  • 防重處理:Redis分布式鎖

方案對比

  • Redis鍵過期回調(diào):實時性最好,但可靠性依賴Redis配置
  • Redisson延時隊列:功能強大,支持分布式,推薦使用
  • ZSet定時掃描:實現(xiàn)簡單,但實時性較差
  • 多級策略:最可靠,但實現(xiàn)復雜

注意事項

  • 一定要配置Redis的notify-keyspace-events Ex
  • 考慮網(wǎng)絡分區(qū)和Redis故障的情況
  • 實現(xiàn)冪等性處理,防止重復取消
  • 添加監(jiān)控和告警
  • 考慮持久化,防止重啟后數(shù)據(jù)丟失

性能優(yōu)化

  • 使用批量處理過期訂單
  • 異步處理過期邏輯
  • 合理設置掃描頻率
  • 使用連接池

這種實現(xiàn)可以確保訂單過期功能的可靠性和實時性,適合電商等高并發(fā)場景。

到此這篇關(guān)于springboot+redis實現(xiàn)訂單過期(超時取消)功能的方法詳解的文章就介紹到這了,更多相關(guān)springboot訂單超時取消內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA 使用 SpotBugs 找出你代碼中的bug問題

    IDEA 使用 SpotBugs 找出你代碼中的bug問題

    這篇文章主要介紹了IDEA 使用 SpotBugs 找出你代碼中的bug問題,重點給大家介紹SpotBugs 在 idea 中的安裝和使用,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • java整合socket通信的完整步驟記錄

    java整合socket通信的完整步驟記錄

    在Java編程中Socket通信是實現(xiàn)網(wǎng)絡應用程序之間通信的基礎(chǔ),Socket是TCP/IP協(xié)議的一部分,它提供了進程間的網(wǎng)絡通信,這篇文章主要介紹了java整合socket通信的相關(guān)資料,需要的朋友可以參考下
    2025-07-07
  • mac下idea啟動web項目報錯java.net.SocketException:socket closed問題

    mac下idea啟動web項目報錯java.net.SocketException:socket closed

    本文主要介紹了作者在項目啟動時遇到的一個問題——無法打開調(diào)試端口,經(jīng)過一系列排查和嘗試,最終發(fā)現(xiàn)是由于權(quán)限問題導致的,作者還分享了如何修改文件權(quán)限的方法,并提醒大家不要隨意kill掉占用端口的進程
    2024-12-12
  • spring利用squertz實現(xiàn)定時任務

    spring利用squertz實現(xiàn)定時任務

    spring squertz是一個強大的定時任務處理方式。下面這篇文章主要介紹了spring利用squertz實現(xiàn)定時任務的相關(guān)資料,文中介紹的很詳細,對大家具有一定的參考借鑒價值,需要的朋友們下面來一起看看吧。
    2017-01-01
  • SpringBoot繼承LogStash實現(xiàn)日志收集的方法示例

    SpringBoot繼承LogStash實現(xiàn)日志收集的方法示例

    這篇文章主要介紹了SpringBoot繼承LogStash實現(xiàn)日志收集的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • IDEA如何將String類型轉(zhuǎn)json格式

    IDEA如何將String類型轉(zhuǎn)json格式

    在Java中,字符串字面量中的轉(zhuǎn)義字符會被自動轉(zhuǎn)換,但通過網(wǎng)絡獲取的字符串可能不會自動轉(zhuǎn)換,為了解決IDEA無法識別JSON字符串的問題,可以在本地對字符串進行一次轉(zhuǎn)換,替換轉(zhuǎn)義字符,從而生成可以被IDEA識別的新JSON字符串
    2025-01-01
  • 基于java servlet過濾器和監(jiān)聽器(詳解)

    基于java servlet過濾器和監(jiān)聽器(詳解)

    下面小編就為大家?guī)硪黄趈ava servlet過濾器和監(jiān)聽器(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 解決Maven?build打包,類找不到,找不到引用的那個項目里面的類問題

    解決Maven?build打包,類找不到,找不到引用的那個項目里面的類問題

    文章討論了在使用Maven構(gòu)建項目時遇到類找不到的問題,并給出了解決方法,主要原因是公共項目被打成了可執(zhí)行的jar,導致其他項目無法引用其中的類,解決方法包括在公共項目的pom中將打包類型改為普通jar,以及在主項目中正確引用公共項目
    2026-02-02
  • 在Java中基于Geotools對PostGIS數(shù)據(jù)庫的空間查詢實踐教程

    在Java中基于Geotools對PostGIS數(shù)據(jù)庫的空間查詢實踐教程

    本文將深入探討這一實踐,從連接配置到復雜空間查詢操作,包括點查詢、區(qū)域范圍查詢以及空間關(guān)系判斷等,全方位展示如何在 Java 環(huán)境下借助 Geotools 駕馭 PostGIS 數(shù)據(jù)庫,實現(xiàn)高效精準的空間數(shù)據(jù)檢索,為相關(guān)領(lǐng)域開發(fā)者提供實用的技術(shù)路徑,助力空間數(shù)據(jù)應用的創(chuàng)新拓展
    2025-05-05
  • java實現(xiàn)輸出文件夾下某個格式的所有文件實例代碼

    java實現(xiàn)輸出文件夾下某個格式的所有文件實例代碼

    這篇文章主要介紹了java實現(xiàn)輸出文件夾下某個格式的所有文件,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06

最新評論

弥勒县| 平度市| 泰安市| 怀柔区| 石景山区| 偃师市| 朔州市| 陈巴尔虎旗| 于都县| 五莲县| 绥芬河市| 晴隆县| 板桥市| 建水县| 鄄城县| 桦川县| 平远县| 客服| 黑山县| 娄底市| 泌阳县| 巫山县| 濉溪县| 普兰店市| 格尔木市| 柘荣县| 乡宁县| 疏附县| 汤原县| 青州市| 铜川市| 毕节市| 文登市| 林州市| 辽阳市| 富平县| 福鼎市| 山丹县| 宁远县| 奉节县| 贵港市|