У каждого должен быть опыт размещения заказа на Ele.me или Meituan.После того, как заказ будет размещен, заказ будет автоматически отменен через определенный период времени. Это отложенная задача. Сценарии применения отложенных задач достаточно обширны, мало того, что вы голодны, как было сказано выше, Meituan Takeaway, но и 12306, или Taobao, Ctrip и т.д. имеют такие сценарии. Как достигается эта отложенная задача? Следуйте за мной и продолжайте читать.
1. Делайте трюки в SQL-запросе и сборке слоя Serive
Сделайте некоторые суждения на уровне сплайсинга SQL или Serive.Например, статус заказа "заказано, но не оплачен", а текущее время превышает время заказа на 15 минут. Статус заказа, отображаемый на клиенте или в фоновом режиме, меняется на " Отменено." ".
Этот способ более удобен и задержки нет, но состояние в БД не является реальным состоянием. Если вам нужно предоставить интерфейс для вызова других отделов, не забудьте выполнить специальную обработку для этого статуса заказа.
2.Job
Это один из самых распространенных способов. Он заключается в открытии задания, циклическом выполнении заказа время от времени и изменении статуса заказа при выполнении условий.
Этот метод также более удобен, но будет определенная задержка.Если данные заказа относительно небольшие, допустимо сканирование раз в минуту, а задержка составляет всего около одной минуты. Однако, как только данные о заказе большие, они могут не быть отсканированы в течение часа, поэтому задержка довольно ужасающая. И постоянно сканировать базу — это тоже некое давление на базу. Конечно, можно внести некоторые улучшения, такие как добавление диапазона времени при сканировании, а заказы до определенного времени не сканируются, потому что эти заказы были обработаны последним запущенным заданием.
Первый метод можно использовать в сочетании со вторым методом.
Первые два — более привычные практики, если объем данных невелик, то неплохо использовать.
3.DelayQueue
DelayQueue — это собственная очередь Java, и из названия можно понять, что это очередь с задержкой.Из приведенного выше рисунка видно, что DelayQueue — это общая очередь, и тип, который она принимает, унаследован от Delayed. То есть нам нужно написать класс для наследования (реализации) Delayed. Чтобы реализовать Delayed, вам нужно переопределить два метода:
public long getDelay(TimeUnit unit)
public int compareTo(Delayed o)
Первый метод: основа для оценки того, истек ли срок действия сообщения (можно ли его прочитать). Когда возвращается отрицательное число, срок действия сообщения истек, и его можно прочитать.
Второй метод: вставка данных в DelayQueue вызовет выполнение этого метода, который является основой для принятия решения о том, куда следует поместить данные.
В этом классе нам нужно определить некоторые свойства, такие как orderId, orderTime (время заказа), expireTime (время задержки).
Теперь давайте сначала пройдем тест, проверьте метод сравнения:
public class OrderDelay implements Delayed {
private int orderId;
private Date orderTime;
public Date getOrderTime() {
return orderTime;
}
public void setOrderTime(Date orderTime) {
this.orderTime = orderTime;
}
private static final int expireTime = 15000;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
@Override
public long getDelay(TimeUnit unit) {
return orderTime.getTime() + expireTime - new Date().getTime();
}
@Override
public int compareTo(Delayed o) {
return this.orderTime.getTime() - ((OrderDelay) o).orderTime.getTime() > 0 ? 1 : -1;
}
}
Метод getDelay пока не видно, потому что тесту CompareTo не нужно использовать этот метод. Затем мы пишем код в основном методе:
DelayQueue<OrderDelay> queue = new DelayQueue<>();
Calendar c = Calendar.getInstance();
c.add(Calendar.DATE, 1);
Date time1 = c.getTime();
OrderDelay orderDelay1=new OrderDelay();
orderDelay1.setOrderId(1);
orderDelay1.setOrderTime(time1);
queue.put(orderDelay1);
System.out.println("1: "+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time1));
c.add(Calendar.DATE, -15);
Date time2 = c.getTime();
OrderDelay orderDelay2=new OrderDelay();
orderDelay2.setOrderId(2);
orderDelay2.setOrderTime(time2);
queue.put(orderDelay2);
System.out.println("2: "+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time2));
int a=0;
Установите точку останова в последней строке, а затем выполните отладку. Вы обнаружите, что хотя order1 сначала помещается в DelayQueue, первые данные DelayQueue — это order2, что и является целью метода compareTo:
Определите, где данные должны быть основаны на возвращаемом значении этого метода.Вообще говоря, чем меньше значение orderTime, тем раньше истечет срок его действия и тем раньше оно будет использовано, поэтому с этим методом проблем нет.
Тест compareTo завершен, давайте завершим код, а затем протестируем метод getDelay (в этот раз нужно обратить внимание на код в методе getDelay): Сначала определите метод производителя:
private static void produce(int orderId) {
OrderDelay delay = new OrderDelay();
delay.setOrderId(orderId);
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
delay.setOrderTime(currentTime);
System.out.printf("现在时间是%s;订单%d加入队列%n", dateString, orderId);
queue.put(delay);
}
Определите другой потребительский метод:
private static void consum() {
while (true) {
try {
OrderDelay orderDelay = queue.take();//
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
System.out.printf("现在时间是%s;订单%d过期%n", dateString, orderDelay.getOrderId());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Запустите эти два метода внутри основного метода:
produce(1);
consum();
Тогда точка останова установлена
OrderDelay orderDelay = queue.take();
Отладьте, запустите здесь, F8, вы обнаружите, что код не может быть выполнен и заблокирован, На самом деле это также показывает, что DelayQueue является блокирующей очередью. Через 15 секунд я, наконец, ввел следующую строку кода и получил данные, что и является целью методов getDelay и take. getDelay: По возвращаемому значению метода определите, можно ли извлечь данные. take: вынуть данные, но это ограничено методом getDelay, при невыполнении условий - заблокируется.
Хорошо. Метод getDelay и compareTo были протестированы. Следующие вещи просты. Я просто выложил код:
static DelayQueue<OrderDelay> queue = new DelayQueue<>();
public static void main(String[] args) throws InterruptedException {
Thread productThread = new Thread(() -> {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
e.printStackTrace();
}
produce(i);
}
});
productThread.start();
Thread consumThread = new Thread(() -> {
consum();
});
consumThread.start();
}
private static void produce(int orderId) {
OrderDelay delay = new OrderDelay();
delay.setOrderId(orderId);
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
delay.setOrderTime(currentTime);
System.out.printf("现在时间是%s;订单%d加入队列%n", dateString, orderId);
queue.put(delay);
}
private static void consum() {
while (true) {
try {
OrderDelay orderDelay = queue.take();//
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
System.out.printf("现在时间是%s;订单%d过期%n", dateString, orderDelay.getOrderId());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
бегать:
Через вывод консоли вы обнаружите, что реализация функции в порядке.
Этот способ и удобнее, и задержки почти нет, и памяти много не занимает, ведь в нем хранится только номер заказа. Недостаток тоже более очевиден, потому что заказ хранится в памяти, как только сервер зависнет, это будет хлопотно. Потребители и производители могут быть только в одном наборе кода.Сейчас эра микросервисов.Вообще говоря,потребители и производители разделены, даже на разных серверах. Из-за этого, если давление потребителей слишком велико, его можно легко решить, добавив сервер.
Первые три метода также можно использовать в комбинации.