[英]LazyInitializationException with OneToMany in the simpliest way
[英]Random LazyInitializationException with @OneToMany
我有一個具有以下表的舊數據庫:
Police
id (PK)
data...
Contract
id(PK)
version(PK)
type
Code
tab(PK)
code(PK)
name
我有一個JPA實體警察
@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;
}
在代碼表中,有許多用於不同應用程序的不同鍵/值。 在我的情況下,我需要一個,其中“ 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。 其他時間它起作用。
有什么想法嗎? 為什么它不會一直失敗?
剛遇到這個。 關鍵字是“隨機”。 我的一位同事在她的筆記本電腦上始終遇到這種異常,而我從未遇到過。 她只能在IE&Edge上重現異常。
最終意識到它與Tomcat版本有關。 她運行的是舊版本,而我的運行是8.5.8。 她將本地Tomcat升級到此版本,並且不再遇到例外。
確保帶有println的代碼在事務中。
LazyInitializationException
意味着您已在某個事務中加載了實體,退出該實體,然后嘗試使用此實體的某些延遲加載的屬性。
由於您的整個代碼不在此處,因此我假設您的姓名查詢並不總是返回相同的實體,並且當返回的實體包含某些Code
它將引發錯誤。
您的交易必須關閉,否則您將不會收到懶惰的初始化問題。
您應該檢查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()
使用某種單例模式,請確保它是線程安全的。
您也可以嘗試通過調用em.getTransaction().begin()
和em.getTransaction().commit()
將readPolice()
包裝在事務中。 例如:
private static void readPolice(EntityManagerFactory emf) throws Exception {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
...
em.getTransaction().commit();
em.close();
}
如果我在Contract實體中覆蓋了equals / hashcode,它將起作用。 為什么問題是隨機發生的...我不明白...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.