我正在设计一个使用Jersey的Java Web应用程序,其中在mysql db中有一个日期时间字段“ future_time”。我也在同一表中将状态字段设置为待处理。 如果当前时间> = future_time,我想将状态字段更新为在db中完成。就像我要安排一个活动。
第二,如果current_ time 当前,每当我获取状态字段时,我都会检查状态字段是否未决,如果未完成,那么我将检查future_time <= current_time,如果是,则将db中的状态字段更新为已完成。但这是有问题的。当我获取状态字段时,这只会更新状态字段。因此,如果我在很长一段时间(future_time之后)之后获取状态字段,那么它将在那一刻进行更新,将错误的记录保存在db中。 有人能建议我实现这一目标的更好方法吗?
答案 0 :(得分:0)
您可以使用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
。以下是使用Timer计划作业的示例代码。
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's 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调度。
答案 1 :(得分:0)
在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 framework而不是传统的Timer
类。在Servlet或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.
(可选)您可以捕获此schedule
语句返回的ScheduledFuture
。然后,您可以监视完成状态。
在您的Runnable
中,从数据库中检索当前状态记录。如果有必要,请安排另一个执行时间,并使用新的当前时刻重新计算等待时间。
对于没有完整web container堆栈的Servlet Jakarta.ee(例如 Tomcat 或 Jetty ),适用以上讨论。
此外,您将需要编写一个实现ServletContextListener
接口的类,您可以在其中设置和拆除执行程序服务。您需要适当地关闭执行程序服务,以使其后台线程在您的Web应用程序关闭后很长一段时间内不会继续正常运行。
如果使用成熟的Jakarta.ee堆栈(例如Glassfish),则这项工作会容易得多。
上面显示的执行程序服务可以自动化,代表您执行设置和拆卸。使用JSR 236: Concurrency Utilities for JavaTM EE中定义的并发实用程序。这已经被覆盖了很多次,因此请搜索Stack Overflow以获取更多信息。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。