我正在使用 JPA 的 Hibernate 實作。假設我有一個物件串列,我必須將其保存在一個名為 Event 的表中。所有這些物件都有相同的郵政編碼。
public class Event {
String id;
String zipCode;
String locationCode;
String eventName;
String eventDesc;
}
這id是主鍵,zipCode并locationCode一起構成唯一鍵(UK_zipCode_locationCode)。該表可能已經包含具有給定郵政編碼的物件。因此,我要做的不是查找??應該添加、洗掉或更新哪些物件,而是首先洗掉表中具有給定郵政編碼的所有物件,然后插入所有給定物件。
// getEventsToAdd method returns the list of events to be added for the zipCode 1234
// getEventsFromTheDB method returns all the events in the db with the zipCode 1234
List<Event> eventsToAdd = getEventsToAdd("1234");
List<Event> oldEvents = getEventsFromTheDB("1234");
for (Event e : oldEvents) {
entityManager.remove(e);
}
for (Event e : eventsToAdd) {
entityManager.persist(e);
}
entityManager.flush();
// ...
當oldEvents串列為空或串列中的所有物件oldEvents也在eventsToAdd串列中時(我的意思是具有相同 id 和相同郵政編碼的事件物件),此方法有效。
但是,如果有一些事件物件oldEvents具有不同的id,即與串列中任何物件的id都不匹配eventsToAdd,則拋出例外
Duplicate Entry found for key UK_zipCode_locationCode
錯誤好像舊事件沒有從表中洗掉,現在插入具有相同 zipCode 和 locationCode 值的事件導致org.hibernate.exception.ConstraintViolationException。
但是,如果我entityManager.flush()在洗掉舊事件后呼叫,它會起作用 -
// This works!
for (Event e : oldEvents) {
entityManager.remove(customizedProviderAttribute);
}
// flush after removing all the old events
entityManager.flush();
for (Event e : eventsToAdd) {
entityManager.persist(e);
}
那么,為什么最后重繪 不起作用,但洗掉舊物體后重繪 起作用呢?
uj5u.com熱心網友回復:
默認情況下,EntityManager 在事務提交時執行所有 SQL 命令。但是,它可以決定執行 SQL 命令的順序,并且在您的情況下,插入是在洗掉之前完成的,這會導致ConstraintViolationException. flush()導致所有 SQL 立即執行,因此您可以在插入之前實作洗掉。世界并不完美,Hibernate 也不完美。
uj5u.com熱心網友回復:
當您呼叫 remove 和 persist 時,物體管理器不一定會發出 delete 和 insert 陳述句,它會等待并稍后生成 SQL,通常是在您顯式或隱式重繪 時。這意味著陳述句的順序會有所不同,因此某些插入可能會在某些洗掉之前執行,從而觸發約束違規。在這種情況下,您使用中間重繪 的解決方法是常見的做法。
uj5u.com熱心網友回復:
在您的第二個作業示例中,當您在洗掉后重繪 時,Hibernate 會將這些物體的狀態更改為 REMOVED,以便在物理上完成洗掉時與資料庫保持同步,并且在您的日志中,您將看到發出的洗掉 sql 查詢,這就是為什么當你堅持那些相同的物體時,它會起作用,因為第一個例子不起作用,因為這些物體仍處于 MANAGED 狀態,而你試圖再次堅持它們,這會導致重復的條目,就像@Michal 說的那樣,在洗掉之前發出的插入,因為不能保證順序。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/467752.html
上一篇:如何在JPA中撰寫多個聯接?
下一篇:自定義識別符號生成器回傳null
