2012-04-12 105 views
4

我需要刪除一個實體,創建另一個:JPA:EclipseLink的不尊重em.remove()

@Stateless 
public class StatelessBean { 
    @PersistenceUnit(unitName = "Unit001") 
    EntityManagerFactory emf; 

    protected void test() { 
    EntityManager em = emf.createEntityManager(); 
    MyObj obj1 = em.find(MyObj.class, 100); 
    MyObj obj2 = new MyObj(); 
    obj2.setKey("the same unique key as in obj1"); 
    em.remove(obj1); 
    // em.flush(); 
    em.persist(obj2); // works fine when flush() is uncommented 
    em.close(); 
    } 
} 

如果我離開em.flush()評論,然後我得到com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException(新舊對象具有相同的鍵值)

什麼可能是這種異常行爲的原因?

服務器:Glassfish的3.1.2

Eclipse持久服務 - 2.3.2.v20111125-r10461

的persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> 
    <persistence-unit name="Unit001"> 
    <jta-data-source>jdbc/Unit001DS</jta-data-source> 
    <properties> 
     <property name="eclipselink.logging.level" value="INFO"/> 
     <property name="eclipselink.target-database" value="MySQL"/> 
    </properties> 
    </persistence-unit> 
</persistence> 

連接池:

${ASADMIN} --port ${DOMAIN_ADMIN_PORT} create-jdbc-connection-pool --datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property "User=user:Password=pass:URL=jdbc\:mysql\://${DB_ADDRESS}/db" Unit001DS 
${ASADMIN} --port ${DOMAIN_ADMIN_PORT} create-jdbc-resource --connectionpoolid Unit001DS jdbc/Unit001DS 

回答

5

原因可能是Eclipselink在提交期間改變了操作的順序,如上所述Eclipselink documentation

默認情況下,它的EclipseLink插入和更新操作第一,刪除操作前,要確保引用完整性得以維持。這是首選的方法。

您可以通過刷新(因爲你已經發現了),或者通過設置的EclipseLink的特殊參數更改此行爲:

如果你被迫通過 刪除,以取代具有唯一約束的對象它並插入替換,如果插入操作發生在刪除操作之前,則可能會導致違反約束 。 在這種情況下,請在插入操作之前調用setShouldPerformDeletesFirst執行刪除 操作。

+0

謝謝,但'其他JPA實現以同樣的方式執行相同的操作對我來說有點令人質疑 - 同樣的項目非常好地運行'Hibernate'作爲JPA提供程序。 – Osw 2012-04-12 09:24:58

+0

您可能是對的,我不確定,只需在另一篇文章中閱讀即可。將編輯我的答案。 – 2012-04-12 09:29:17

+0

是否有任何配置選項強制eclipselink生成sql作爲java代碼流?我很低調,希望能夠兼容hibernate的解決方案,而無需調整sql-deletes。 – Osw 2012-04-12 09:35:55

1

EclipseLink的維護和優化承諾爲:

1 - 保持參照完整性約束:如果您將兩個相關對象(或多個對象的一個​​大的互連圖),它們必須被插入/更新/以非常明確和不明顯的順序刪除,以維護參照完整性約束。在某些情況下,甚至可能需要插入shell對象並在解決循環依賴性之後更新其外鍵。刪除必須最後出現,因爲用於引用已刪除對象的對象必須先更新關係。

2 - 組操作和表訪問:這可以避免數據庫死鎖,並允許批量寫入的最佳使用。

3 - 始終按順序排列更新/刪除操作:這是可配置的,可避免潛在的數據庫死鎖。

如果EclipseLink只是盲目地按照應用程序的順序編寫的東西,那麼您必須自己管理所有這些。我真的懷疑你真的想這樣做。對於你確實需要的情況,你可以使用flush()。

+0

對不起,我只是不相信。我們談論的是JPA的實施,而不是AI,不是嗎?必須以某種方式尊重'EntityManager'調用的流程,否則我的所有事務都將能夠以兩個無序集合「toPersist」和「toDelete」結束。如果我在這個特定的代碼行中說'刪除',那麼這對於JPA提供者來說意味着什麼。我對嗎? – Osw 2012-04-12 14:33:37