我有一个带有主键(ID)的Job实体。 我坚持让它获得id。 然后我更新需要ID的字段(ImgWorkName)。
大部分时间(如1000次中的999次)一切正常。 但是有时(比如1000次中的1次)当我在JPA中进行后续查询时,已经设置了更新的字段! 该字段位于数据库中(因此,如果我重新启动应用程序,我将始终看到更新的字段)
我是一位经验丰富的程序员。 我已经在这个问题上苦苦挣扎了一年多了,所以我真的很高兴能得到一些帮助!
问题开始出现在3 - 4年前,但很少,然后慢慢地这个错误突然出现,所以现在它几乎每天都会发生。
一个月前,我将服务器从Ubuntu 12升级到Ubuntu 16 - 没有区别。
一个月前,我从Java 6升级到Java 8 - 没有区别。
然后我将7年前的JPA库升级到JPA 2.1并升级到最新的Tomcat 7 - 没有区别。
这些年来,数据库越来越大。 MySQL Job表中现在有大约100万行,但查询只返回大约600行。 对我来说这似乎是一个JPA错误,但我找不到有类似问题的人。
以下是相关的代码段。提前谢谢!
@Entity
@Table(name = "job")
public class Job implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "imgOrgName", length = 300)
private String imgOrgName;
@Column(name = "imgWorkName", length = 100)
private String imgWorkName;
@Column(name = "created")
@Temporal(TemporalType.TIMESTAMP)
private Date created;
@Column(name = "todoFileSize")
private Integer todoFileSize;
// more fields, getters and setters
}
public class FF {
public EntityManagerFactory emf = javax.persistence.Persistence.createEntityManagerFactory(emfNavn);
public EntityManager emq = emf.createEntityManager();
// Bad workaround
private LinkedHashMap<Integer, Job> jobIdTilJobWorkaround = new LinkedHashMap<Integer, Job>();
private void scanCustomerTodoDir() {
EntityManager emEnqueueJobs = emf.createEntityManager();
try {
// Add all files as jobs (we dont know the new jobids yet)
emEnqueueJobs.getTransaction().begin();
ArrayList<Job> jobs = new ArrayList<Job>();
for (Path f : subfiles) {
Job j = new Job();
j.file_tmp = f;
j.setTodoFileSize((int) f.toFile().length());
j.setCreated(new Date());
j.setUser(user);
j.setService(service);
j.setImgOrgName(imgOrgName);
j.setState("QUEUED");
jobs.add(j);
emEnqueueJobs.persist(j);
}
// commit to get all jobids
emEnqueueJobs.getTransaction().commit();
for (Job j : jobs) {
emEnqueueJobs.getTransaction().begin();
// Use the Job ID to decide file name
File fn = new File("/some/path/and/stuff_"+j.getId());
j.setImgWorkName(fn.getName()); // This update gets lost!
emEnqueueJobs.merge(j);
emEnqueueJobs.getTransaction().commit();
jobIdTilJobWorkaround.put(j.getId(), j); // BAD workaround for unfinishedJobsq missing the ImgWorkName in the merge!
}
} finally {
emEnqueueJobs.close();
}
}
public Query unfinishedJobsq = emq.createNativeQuery("select * from ff.job WHERE state = 'QUEUED' OR state = 'GROUPWAIT' ORDER BY id DESC", Job.class);
private void scanServiceproviderDoneDir() {
List<Job> unfinishedJobs = unfinishedJobsq.getResultList();
for (Job j : unfinishedJobs) try {
if (j.getImgWorkName() == null) { // error! This happens sometimes!
Job j2 = jobIdTilJobWorkaround.get(j.getId());
// BAD workaround code for broken JPA (missing the ImgWorkName) here
j = j2;
}
if (...) { // The commit below always works/merges
EntityManager emJobState = emf.createEntityManager();
emJobState.getTransaction().begin();
j.setState("DONE");
long str = doneFile.length();
j.setDoneFileSize((int) str);
j.setDone(new Date());
emJobState.merge(j);
emJobState.getTransaction().commit();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="ffprod" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>ff.db.User</class>
<class>ff.db.Job</class>
<properties>
<property name="eclipselink.jdbc.native-sql" value="false"/>
<property name="eclipselink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="eclipselink.jdbc.url" value="jdbc:mysql://localhost/ff"/>
<property name="eclipselink.jdbc.user" value="ff"/>
<property name="eclipselink.logging.level" value="INFO"/>
<property name="eclipselink.logging.timestamp" value="false"/>
<property name="eclipselink.logging.exceptions" value="true"/>
<property name="eclipselink.logging.thread" value="false"/>
</properties>
</persistence-unit>