JPA:有时会错过合并

时间:2017-05-22 10:56:15

标签: jpa eclipselink

我有一个带有主键(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>

0 个答案:

没有答案