目錄
定時輪詢
惰性取消
JDK延遲佇列
時間輪
Redis過期回呼
Redis有序集合
任務調度
訊息佇列
首頁 Java java教程 怎樣用Java實現自動取消未支付訂單的功能?

怎樣用Java實現自動取消未支付訂單的功能?

May 10, 2023 am 10:07 AM
java

定時輪詢

資料庫定時輪詢方式,實作想法比較簡單。啟動定時任務,每隔一定時間掃描訂單表,查詢到逾時訂單就取消。

優點:實作簡單。

缺點:輪詢時間間隔不好確定,佔用伺服器資源,影響資料庫效能。

惰性取消

當查詢訂單資訊時,先判斷該訂單是否逾時,如果逾時就先取消。

優點:實作簡單。

缺點:影響查詢以外的業務(如:統計、庫存),影響查詢效率。

JDK延遲佇列

JDK延時佇列DelayQueue是一個無界阻塞佇列,該佇列只有在延遲期滿的時候才能從中取得元素。

簡單實作程式碼demo如下,實際生產過程中會有專門的執行緒負責訊息的入隊與消費。

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
 
/**
 * @author 向振华
 * @date 2022/08/16 15:55
 */
public class OrderDelayed implements Delayed {
 
    /**
     * 延迟时间
     */
    private final Long time;
    /**
     * 订单编号
     */
    public String orderNo;
 
    public OrderDelayed(String orderNo, long time, TimeUnit unit) {
        this.orderNo = orderNo;
        this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);
    }
 
    @Override
    public long getDelay(TimeUnit unit) {
        return time - System.currentTimeMillis();
    }
 
    @Override
    public int compareTo(Delayed o) {
        OrderDelayed orderDelayed = (OrderDelayed) o;
        long diff = this.time - orderDelayed.time;
        if (diff <= 0) {
            return -1;
        } else {
            return 1;
        }
    }
}
登入後複製
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;
 
/**
 * @author 向振华
 * @date 2022/08/16 16:02
 */
public class Test {
 
    public static void main(String[] args) {
 
        DelayQueue<OrderDelayed> delayQueue = new DelayQueue<>();
 
        delayQueue.put(new OrderDelayed("220101001", 8, TimeUnit.SECONDS));
        delayQueue.put(new OrderDelayed("220101002", 4, TimeUnit.SECONDS));
 
        System.out.println("订单延迟队列开始执行");
 
        while (true) {
            // 取队列头部元素是否过期
            OrderDelayed task = delayQueue.poll();
            if (task != null) {
                // 取消订单业务逻辑
                System.out.println("订单 ---> " + task.orderNo + " 已过期准备取消");
            }
        }
    }
}
登入後複製

優點:效率高,任務觸發時間延遲低。

缺點:異常恢復困難,叢集擴展麻煩,記憶體佔用。

時間輪

時間輪演算法類似時鐘,會以某個方向按固定頻率輪動。可以用Netty的HashedWheelTimer來實現時間輪方法。

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.78.Final</version>
</dependency>
登入後複製
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;
 
import java.util.concurrent.TimeUnit;
 
/**
 * @author 向振华
 * @date 2022/08/16 16:02
 */
public class Test {
 
    public static void main(String[] args) {
 
        // 初始化时间轮
        Timer timer = new HashedWheelTimer();
 
        // 定时任务
        TimerTask task1 = new TimerTask() {
            public void run(Timeout timeout) throws Exception {
                // 取消订单业务逻辑
                System.out.println("订单1已过期准备取消");
            }
        };
        // 注册此定时任务(延迟时间为5秒,也就是说5秒后订单过期)
        timer.newTimeout(task1, 5, TimeUnit.SECONDS);
 
        // 定时任务
        TimerTask task2 = new TimerTask() {
            public void run(Timeout timeout) throws Exception {
                // 取消订单业务逻辑
                System.out.println("订单2已过期准备取消");
            }
        };
        // 注册此定时任务(延迟时间为3秒,也就是说3秒后订单过期)
        timer.newTimeout(task2, 3, TimeUnit.SECONDS);
    }
}
登入後複製

優點:效率高,任務觸發時間延遲更低。

缺點:異常恢復困難,叢集擴展麻煩,記憶體佔用。

Redis過期回呼

Redis的key過期回呼事件,也能達到延遲佇列的效果。

在redis.conf加入一條設定:

notify-keyspace-events Ex

監聽設定

@Configuration
public class RedisListenerConfig {
 
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}
登入後複製

Redis過期回呼監聽方法

@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
 
    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }
 
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 过期key,可以设置成订单号
        String expiredKey = message.toString();
        // 取消订单业务逻辑
        System.out.println("订单 ---> " + expiredKey + " 已过期准备取消");
    }
}
登入後複製

優點:資料不易遺失,叢集擴充方便。

缺點:需要額外維護redis。

Redis有序集合

Redis的資料結構Zset,同樣可以實現延遲佇列的效果,主要利用它的score屬性,redis透過score來為集合中的成員進行從小到大的排序。透過zadd指令為佇列delayqueue 中加入元素,並設定score值表示元素過期的時間。

消費端輪詢佇列delayqueue, 將元素排序後取最小時間與目前時間比對,如小於目前時間代表已過期移除key。

public void pollOrderQueue() {
 
    while (true) {
        Set<Tuple> set = jedis.zrangeWithScores(delayqueue, 0, 0);
 
        String value = ((Tuple) set.toArray()[0]).getElement();
        int score = (int) ((Tuple) set.toArray()[0]).getScore();
 
        int nowSecond = System.currentTimeMillis() / 1000);
        if (nowSecond >= score) {
            jedis.zrem(delayqueue, value);
            System.out.println(sdf.format(new Date()) + " removed key:" + value);
        }
 
        if (jedis.zcard(delayqueue) <= 0) {
            System.out.println(sdf.format(new Date()) + " zset empty ");
            return;
        }
        Thread.sleep(1000);
    }
}
登入後複製

優點:資料不易遺失,叢集擴充方便。

缺點:可能重複消費同一key。

任務調度

使用任務調度中間件xxl-job、ScheduleX、Elastic-Job等來實現,設定一個調度時間cron,到達訂單過期的調度時間時,觸發任務執行取消訂單業務邏輯。

例如使用xxl-job實現,訂單建立時提交一個過期任務到xxl-job伺服器,下面時執行器方法:

import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
 
/**
 * @author 向振华
 * @date 2022/08/16 15:55
 */
@Component
public class JobHandler {
 
    @XxlJob("payExpireJobHandler")
    public void payExpireJobHandler(String executorParam) {
        // 取消订单业务逻辑
        System.out.println("订单 ---> " + executorParam + " 已过期准备取消");
    }
}
登入後複製

優點:時效性強,支援分散式。

缺點:實現複雜,維護成本高。

訊息佇列

使用RocketMQ、RabbitMQ、Kafka的延時訊息,訊息在傳送到訊息佇列服務端後並不會立刻投遞,而是根據訊息中的屬性延遲固定時間後才投遞給消費者。

RocketMQ發送延時訊息的範例程式碼如下:

import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.ONSFactory;
import com.aliyun.openservices.ons.api.Producer;
import com.aliyun.openservices.ons.api.PropertyKeyConst;
import com.aliyun.openservices.ons.api.SendResult;
import java.util.Properties;
 
public class Test {
    public static void main(String[] args) {
        Properties properties = new Properties();
        // AccessKey ID阿里云身份验证,在阿里云RAM控制台创建。
        properties.put(PropertyKeyConst.AccessKey, "XXX");
        // AccessKey Secret阿里云身份验证,在阿里云RAM控制台创建。
        properties.put(PropertyKeyConst.SecretKey, "XXX");
        // 设置TCP接入域名,进入消息队列RocketMQ版控制台实例详情页面的接入点区域查看。
        properties.put(PropertyKeyConst.NAMESRV_ADDR,
          "XXX");
 
        Producer producer = ONSFactory.createProducer(properties);
        // 在发送消息前,必须调用start方法来启动Producer,只需调用一次即可。
        producer.start();
        Message msg = new Message( 
                // 您在消息队列RocketMQ版控制台创建的Topic。
                "Topic",
                // Message Tag,可理解为Gmail中的标签,对消息进行再归类,方便Consumer指定过滤条件在消息队列RocketMQ版服务器过滤。
                "tag",
                // Message Body可以是任何二进制形式的数据,消息队列RocketMQ版不做任何干预,需要Producer与Consumer协商好一致的序列化和反序列化方式。
                "Hello MQ".getBytes());
        // 设置代表消息的业务关键属性,请尽可能全局唯一。
        // 以方便您在无法正常收到消息情况下,可通过控制台查询消息并补发。
        // 注意:不设置也不会影响消息正常收发。
        msg.setKey("ORDERID_100");
        try {
            // 延时消息,在指定延迟时间(当前时间之后)进行投递。最大可设置延迟40天投递,单位毫秒(ms)。
            // 以下示例表示消息在3秒后投递。
            long delayTime = System.currentTimeMillis() + 3000;
 
            // 设置消息需要被投递的时间。
            msg.setStartDeliverTime(delayTime);
 
            SendResult sendResult = producer.send(msg);
            // 同步发送消息,只要不抛异常就是成功。
            if (sendResult != null) {
            System.out.println(new Date() + " Send mq message success. Topic is:" + msg.getTopic() + " msgId is: " + sendResult.getMessageId());
            }
            } catch (Exception e) {
            // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理。
            System.out.println(new Date() + " Send mq message failed. Topic is:" + msg.getTopic());
            e.printStackTrace();
        }
        // 在应用退出前,销毁Producer对象。
        // 注意:如果不销毁也没有问题。
        producer.shutdown();
    }
}
登入後複製

RocketMQ延時訊息的訂閱與普通訊息訂閱一致。

優點:高效,好擴展,支援分散式。

缺點:實現複雜,維護成本高。

以上是怎樣用Java實現自動取消未支付訂單的功能?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1671
14
CakePHP 教程
1428
52
Laravel 教程
1331
25
PHP教程
1276
29
C# 教程
1256
24
PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP的影響:網絡開發及以後 PHP的影響:網絡開發及以後 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP與Python:用例和應用程序 PHP與Python:用例和應用程序 Apr 17, 2025 am 12:23 AM

PHP適用於Web開發和內容管理系統,Python適合數據科學、機器學習和自動化腳本。 1.PHP在構建快速、可擴展的網站和應用程序方面表現出色,常用於WordPress等CMS。 2.Python在數據科學和機器學習領域表現卓越,擁有豐富的庫如NumPy和TensorFlow。

See all articles