gpt4 book ai didi

java - 为什么这个数据库同步例程失败?

转载 作者:行者123 更新时间:2023-11-29 08:53:42 25 4
gpt4 key购买 nike

我有一个数据库,用于维护要由各种处理机器处理的作业。其基本架构如下:

+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| EndTime | datetime | YES | | NULL | |
| GroupID | varchar(255) | NO | MUL | NULL | |
| HostAddress | varchar(15) | YES | | NULL | |
| StartTime | datetime | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+

ID 是自动递增的,HostAddress 代表声明该 Job 的处理机,StartTime 代表最近一次尝试处理该 Job 的开始时间,EndTime 是成功完成处理的时间,GroupID 是任意字符串用于引用其他表格。

所有加工机器都围绕该工作台同步进行抓取工作。尽管所有处理机器都可以更新现有记录,但新记录只能手动插入。我们的想法是让加工机器在停止工作时执行以下操作:

  • 查看是否有属于它的作业(HostAddress = 其 IP)且尚未启动。
  • 如果没有,请查看是否还有尚未申请的职位(HostAddress IS NULL)。
  • 如果有无人认领的职位,请认领一些职位(将 HostAddress 更新为其 IP)。
  • 处理属于它的所有作业(与 #1 相同的检查,除了我们可能通过 #3 添加了一些作业)。

我原以为这一系列操作会导致数据库为我同步不同机器对同一作业的尝试;即使两台机器试图同时申请相同的作业,只有一个 IP 会出现在 HostAddress 列中,因此当它们再次请求其 HostAddress 上的所有作业时,只有其中一台会取回该作业。/p>

但事实似乎并非如此。昨晚,当几乎同时启动 35 台处理机器时,我观察到多台机器处理同一作业的多个案例,尽管其中只有一台机器最终在数据库中声明了该作业。这对我来说意味着最后一次检查无法正常工作。这是我正在做的事情的更具体版本。数据库调用使用 em.createNamedQuery ,为简洁起见,我将在下面对其进行总结。 JPA由Hibernate 3.6.8提供,数据库为MySQL 5.1.61。

protected void poll(EntityManager em) {
List<JobRecord> candidates = null;
//Synchronized only for this machine. Others are running concurrently.
synchronized (em) {
//Check if anything is already claimed by us.
candidates = JobRecord.selectReady(em);
//SELECT record FROM JobRecord record WHERE HostAddress=[IP]
// AND StartTime IS NULL AND EndTime IS NULL;
if (candidates.isEmpty()) {
//None claimed. Check if any jobs aren't claimed by anyone.
candidates = JobRecord.selectAvailable(em);
//SELECT record FROM JobRecord record WHERE HostAddress IS NULL
// AND StartTime IS NULL AND EndTime IS NULL;
if (candidates.isEmpty()) {
//All jobs have been processed.
return;
}
//Claim these jobs we found for ourselves.
em.getTransaction().begin();
for (JobRecord job : candidates) {
job.setStartTime(null);
job.setEndTime(null);
job.setHostAddress([IP]);
em.merge(job);
}
em.getTransaction().commit;
//Only process what is actually claimed by us; could be nothing.
candidates = JobRecord.selectReady(em);
//(The first query again.)
}
//Do processing with candidates list.
}

我想到的唯一解释是,当我执行 em.getTransaction().commit 时,结果会以某种方式缓存,并且当我在它之后执行 selectReady NamedQuery 时,它会返回缓存的结果 懒得查询数据库。但事实可能并非如此,而且我不确定我能否证明这一点。我的计划甚至可能存在一些我忽略的根本缺陷。

那么,实际上提出我的问题,为什么这个数据库同步例程失败以及我可以采取什么措施来纠正它?

最佳答案

多台机器可以在任何一台机器执行UPDATE事务之前调用selectAvailable()。因此,他们可能都认为可以找到相同的工作。

您需要在 selectAvailable() 调用之前开始事务,该调用应使用 SELECT ... FOR UPDATE为了锁定可用的作业记录,以便在提交事务之前没有其他数据库连接可以读取它们。

关于java - 为什么这个数据库同步例程失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10521256/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com