我有一个包含 4 台服务器和 2 台 oracle 数据库服务器的环境,它们之间有用于即时 2 路复制的流。
我有一个 servlet(我无法控制它转到 4 个服务器中的哪一个),它检查作业是否正在运行,如果没有,它会在线程中启动作业。任何时候都应该只运行其中一个作业。我在数据库上放置了一个标志以指示作业正在运行(因为有 4 台服务器,我不能只在内存中保存标志)。
在同步块中,我检查作业是否正在运行,如果没有,我设置一个标志。在此之后我开始工作
synchronized (this)
{
if (statusDao.isJobRunning())
{
throw new JobRunningException("Job is already running");
}
//set flag to indicate that job is running
statusDao.setJobRunningFlag();
}
这适用于只有一台服务器的环境,但不适用于我的场景。
如果我在同步块中的 2 个不同服务器上有一个线程,并且它们都在检查作业没有运行之后,那么它们都将尝试设置标志。因此,我建立了应急机制,以便能够捕获唯一的键约束(每个作业都有一个 id,它是数据库中的主键。我将此值硬编码为 1,以便数据库中只能有一个条目)。我正在使用 Springs JdbcTemplate
try {
this.jobJdbcTemplate.update(insert into JOB (JOB_ID, RUNNING) values ('1','Y'));
}catch (DataAccessException dae){
if (StringUtils.contains(dae.getMessage(), "ORA-00001"))
{
throw new JobRunningException("Job is already running");
}
throw new JobException("Error setting Job Flag.");
}
再说一次,这个功能正确,但我可以想象有更好的方法来做到这一点。你能建议另一种方法吗?在我看来,我需要一些可以锁定数据库的东西(当我检查标志是否正在运行然后设置标志运行时)。请记住,有 2 个数据库,所以我不知道只锁定一个是否有效。我应该查看 Spring 的交易吗?或者你能推荐点别的吗?
谢谢。