使用@OneToMany进行随机LazyInitializationException

时间:2015-03-16 12:57:19

标签: java hibernate jpa

我有一个包含以下表格的遗留数据库:

Police
 id (PK)
 data...

Contract
 id(PK)
 version(PK)
 type


Code
 tab(PK)
 code(PK)
 name

我有一个实体警察

@Entity
public class Police implements Serializable {


@Id
private long id

@OneToMany(fetch = FetchType.LAZY)
@JoinColumns(value = { @JoinColumn(name = "id", referencedColumnName = "id") })
private Set<Contract> contracts;

}

合同实体如下所示:

@Entity
public class Contract implements Serializable {


@Id
private long id;

@Id
private long version;


private String type;



@OneToMany(fetch = FetchType.LAZY)
@JoinColumns({ @JoinColumn(name = "code", referencedColumnName = "type") })
@Where(clause = "tab = 'Type'")
private Set<Code> type;
}

代码:

@Entity
public class Code implements Serializable {


    @Id
    private String tab;
    @Id
    private String code;

    private String name;
}

在Code表中有许多不同应用程序的键/值。 在我的情况下,我需要一个,其中“tab ='Type'”和代码=来自我的合同。

我的问题是,如果我的警察有多个合同,我会随便吗?得到一个org.hibernate.LazyInitializationException。

在我的测试用例中,我执行以下操作:

public static void main(String[] args) {

    int countErrors = 0;

    for (int i = 0; i < 15; i++) {
        try {
            readPolice();
        } catch (Exception e) {
            e.printStackTrace();
            countErrors++;
        }
    }

    System.err.println("errors: " + countErrors);

}

private static void readPolice() throws Exception {
  EntityManagerFactory factory =     EntityManagerFactoryHelper.getFactory(PersistenceUnitsEnum.TEST_STAGE);
  EntityManager em = factory.createEntityManager();
  TypedQuery<Police> namedQuery = em.createNamedQuery(...);
  Police result = namedQuery.getSingleResult();
  Set<Contract> contracts = result.getContract();
  Contract contract = contracts.iterator().next();
  Set<Code> type = contract.getType(); //should be a set with one Entry

  System.out.println(type.size()); //<--- Chance for Exception!!
  em.close();
}

我在循环中尝试了整整15次。 在大约5-8次尝试中,我得到了LazyInitializationException。 其他时候它有效。

对此有何想法?为什么它不会一直失败?

5 个答案:

答案 0 :(得分:1)

刚遇到这个。关键词是'随机'。我的一位同事一直在她的笔记本电脑上遇到这种异常,而我从未遇到过这种情况。她只能在IE&amp; amp;边缘。

终于意识到它与Tomcat版本有关。她正在运行一个旧版本,而我有一个更高版本 - 8.5.8。她将本地Tomcat升级到此版本,不再遇到异常。

答案 1 :(得分:0)

确保使用println的代码在事务中。

LazyInitializationException表示您已经在某个事务中加载了实体,逐步退出它,然后尝试使用该实体的一些延迟加载属性。

答案 2 :(得分:0)

由于您的整个代码不在此处,我假设您的名称查询并不总是返回相同的实体,并且当返回的实体包含一些Code时,它会拖出错误。

您的交易必须关闭,否则您将不会收到懒惰的初始化问题。

答案 3 :(得分:0)

您应该检查EntityManagerFactory的创建是否只执行一次。例如:

public static void main(String[] args) {
  EntityManagerFactory emf = EntityManagerFactoryHelper.getFactory(PersistenceUnitsEnum.TEST_STAGE);
  for (int i = 0; i < 15; i++) {
    readPolice(emf);
  }
}

private static void readPolice(EntityManagerFactory emf) throws Exception {
  EntityManager em = emf.createEntityManager();
  ...
}

如果您在EntityManagerFactoryHelper.getFactory()中使用某种单例模式,请确保它是线程安全的。

您还可以尝试通过调用readPolice()em.getTransaction().begin()em.getTransaction().commit()包含在交易中。例如:

private static void readPolice(EntityManagerFactory emf) throws Exception {
   EntityManager em = emf.createEntityManager();
   em.getTransaction().begin();
   ...
   em.getTransaction().commit();
   em.close();
}

答案 4 :(得分:0)

如果我覆盖Contract实体中的equals / hashcode,它就可以工作。 为什么问题随机发生......我不明白......