Я проектирую веб-приложение на Java с использованием трикотажа, в котором у меня есть поле даты и времени, "future_time" в mysql db. У меня также есть поле состояния в той же таблице, установленное в ожидании. Я хочу обновить поле статуса до завершенного в дБ, если текущее время> = future_time. Как будто я хочу запланировать событие.
Во-вторых, если current_time <future_time и если я обновил значение future_time, я бы хотел перенести предыдущее событие.
В настоящее время всякий раз, когда я получаю поле состояния, я проверяю, ожидает ли оно ожидания, ожидает ли оно, тогда я проверяю, находится ли future_time <= current_time, если так, тогда я обновляю поле состояния в db до завершенного. Но в этом есть проблема. Это только обновит поле состояния, когда я получу его. Поэтому, если я получу поле состояния через долгое время (после future_time), оно будет обновлено в тот момент, сохраняя неправильные записи в дБ.
Может кто-нибудь предложить мне лучший способ достичь этого?
В JDBC 4.2 и более поздних версиях извлекайте дату и время, используя современные классы java.time.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ); // Likely to be a UTC value.
Получить текущий момент.
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ) ;
Рассчитать прошедшее время.
Duration d = Duration.between( now , odt ) ;
Используйте современную среду Executor, а не унаследованный класс Timer
. Это особенно верно в среде сервлетов или Jakarta.ee(Java EE).
Определите вашего исполнителя, в частности, ScheduledExecutorService
. Нам нужна только одна нить для этой задачи.
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
Попросите этого исполнителя подождать определенное время, а затем запустите свой код, чтобы проверить состояние в базе данных.
myExecutorService.schedule( // Tell the executor what you want to run, and when you want it run on your behalf in a background thread.
new Runnable() { … } , // Define task to be executed as a 'Runnable'.
d.toSeconds() , // Amount of time to wait until execution. Use self-documenting code rather than a "magic number" such as '86400000'.
TimeUnit.SECONDS // Specify the granularity of time used in previous pair of arguments.
) // Returns a 'ScheduledFuture' which you may want to cache.
При желании вы можете захватить ScheduledFuture
возвращаемое этим оператором schedule
. Затем вы можете отслеживать статус завершения.
В вашем Runnable
текущую запись о состоянии из вашей базы данных. Если это оправдано, запланируйте другое выполнение, пересчитав время ожидания, используя новый текущий момент.
Для веб-контейнера сервлета, такого как Tomcat или Jetty без полного стека Jakarta.ee, применимо приведенное выше обсуждение.
Кроме того, вы захотите написать класс, который реализует интерфейс ServletContextListener
где вы можете настроить и свернуть службу исполнителя. Вам нужно аккуратно разорвать службу executor, чтобы ее фоновый поток не продолжал весело продолжаться долго после завершения работы вашего веб-приложения.
Если в полномасштабном стеке Jakarta.ee, таком как Glassfish, эта работа намного проще.
Описанная выше услуга для исполнителя может быть автоматизирована с настройкой и демонтажем от вашего имени. Используйте утилиты параллелизма, определенные в JSR 236. Утилиты параллелизма для JavaTM EE. Это было рассмотрено много раз, поэтому ищите переполнение стека для получения дополнительной информации.
Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытеснять неприятные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
, и SimpleDateFormat
.
Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.
Чтобы узнать больше, смотрите Oracle Tutorial. И поиск для многих примеров и объяснений. Спецификация JSR 310.
Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.*
.
Где взять классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти некоторые полезные классы, такие как Interval
, YearWeek
, YearQuarter
и другие.
schedule
возвращает ScheduledFuture
, как упомянуто в моем Ответе. Используйте этот объект для контроля завершения и отмены, если это необходимо.
Вы можете использовать ScheduledExecutorService
для планирования задач на определенный интервал времени, после некоторых фиксированных задержек или в определенный момент времени.
Вы можете создать ScheduledExecutorService
как:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
А затем используйте сервис для планирования заданий, таких как:
//scheduling at fixed time.
Future<String> resultFuture = executorService.schedule(new Callable<String>() {
@Override
public String call() throws Exception
{
//your code;
}
}, 1, TimeUnit.SECONDS);
//scheduling at fixed intervals.
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run()
{
//your code
}
}, 100, 450, TimeUnit.MILLISECONDS);
//scheduling at fixed delays.
executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run()
{
//your code
}
}, 100, 150, TimeUnit.MILLISECONDS);
Вы также можете использовать Java Timer Utility для планирования задач на будущее, но спецификация Java говорит, что предпочтительнее ScheduledExecutorService
. Ниже приведен пример кода для планирования заданий с помощью таймера.
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;
/**
* An example for Java Timer Utility.
*
* @author Karan Khanna.
*/
public class TimerExample
{
public static void scheduleTaskForFuture(final Date date)
{
Timer timer = new Timer("Timer");
TimerTask task = new TimerTask()
{
public void run()
{
System.out.println(
String
.format("Task performed on: %s and Thread name: %s", date, Thread.currentThread().getName()));
timer.cancel();
}
};
timer.schedule(task, date);
}
public static void main(final String[] args)
{
Calendar calendar = new GregorianCalendar();
calendar.add(Calendar.MINUTE, 1);
TimerExample.scheduleTaskForFuture(calendar.getTime());
}
}
Вы можете изучить утилиту больше, чтобы запланировать повторные задачи. Кроме того, не забудьте отменить задание после выполнения необходимой работы.
Для этой цели вы также можете попробовать другие фреймворки, такие как Quartz и Spring.
Timer
рекомендует вместо этого использовать среду Executor .