我有一个包含以下表格的遗留数据库:
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。 其他时候它有效。
对此有何想法?为什么它不会一直失败?
答案 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,它就可以工作。 为什么问题随机发生......我不明白......