2012-11-12 60 views
0

請analize以下兩個代碼,並告訴我,爲什麼這樣做時提交的第一個失敗,並主鍵衝突,而第二個簡化版,。這在失敗JPA合併刪除查詢失敗後

代碼提交:

try{ 

     Query q = em.createQuery("DELETE FROM Puntaje"); 
     q.executeUpdate(); 
     //em.getTransaction().commit(); 

     //em.getTransaction().begin(); 
     Iterator it = l.iterator(); 
     while(it.hasNext()){ 
      DataPuntaje dp = (DataPuntaje)it.next(); 
      Cliente c = new Cliente(dp.getCliente()); 
      Puntaje p = new Puntaje(dp.getPuntaje(),c); 
      c.agregarPuntaje(p); 

      em.merge(c); 

     } 


    System.out.println("test1"); 
     em.getTransaction().commit(); 
    System.out.println("test2"); 
    } 

代碼工作正常:

try{ 

     Query q = em.createQuery("DELETE FROM Puntaje"); 
     q.executeUpdate(); 
     em.getTransaction().commit(); 

     em.getTransaction().begin(); 
     Iterator it = l.iterator(); 
     while(it.hasNext()){ 
      DataPuntaje dp = (DataPuntaje)it.next(); 
      Cliente c = new Cliente(dp.getCliente()); 
      Puntaje p = new Puntaje(dp.getPuntaje(),c); 
      c.agregarPuntaje(p); 

      em.merge(c); 

     } 


    System.out.println("test1"); 
     em.getTransaction().commit(); 
    System.out.println("test2"); 
    } 

唯一的區別是,第一個沒有犯被刪除查詢,而是提交它一起最後。 Cliente和Puntaje是級聯= ALL的1:N雙向關係。 所有插入的Cliente實例都有相同的ID,但合併應該足夠聰明,以便在第一個實例被保留後更新而不是插入,但是在第一個實例中似乎失敗了,我找不到任何解釋。 也即時使用H2嵌入式數據庫。

此外,我想補充,第一個代碼工作正常,如果有一個已插入Cliente值,這在表實際上是空的,所以刪除實際上什麼都不做失敗。

這是錯誤即時得到:

Internal Exception: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_5 ON PUBLIC.CLIENTE(NICK)"; SQL statement: 
INSERT INTO CLIENTE (NICK) VALUES (?) [23505-169] 
Error Code: 23505 
Call: INSERT INTO CLIENTE (NICK) VALUES (?) 
     bind => [cbaldes] 
Query: InsertObjectQuery([email protected]) 
javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_5 ON PUBLIC.CLIENTE(NICK)"; SQL statement: 
INSERT INTO CLIENTE (NICK) VALUES (?) [23505-169] 
Error Code: 23505 
Call: INSERT INTO CLIENTE (NICK) VALUES (?) 
     bind => [cbaldes] 
Query: InsertObjectQuery([email protected] 

這些都是表:

@Entity 
public class Puntaje implements Comparable, Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    private int total; 

    @ManyToOne(cascade=CascadeType.ALL, optional = false) 
    @JoinColumn(name="NICK") 
    private Cliente cliente; 


@Entity 
public class Cliente implements Serializable { 

    @Id 
    private String nick; 

    @OneToMany(cascade=CascadeType.ALL, mappedBy="cliente") 
    private List<Puntaje> puntajes; 
+0

你收到一個主鍵衝突的「Cliente」或「Puntaje」?你可以發佈你的stacktrace嗎? – Sashi

+0

是的,主鍵異常,似乎它不夠聰明,只能插入一次,然後更新所有其餘的,它試圖插入每一個合併,這是奇怪的,因爲刪除什麼都不做,它只是失敗。 – user1777914

回答

2

當你在對象上執行操作,所有的操作都記錄在僅緩存。 JPA將準備要插入,更新和刪除的所有對象的內部列表。flushcommit被調用時,它將被刷新在一起。

現在把你的第一個例子。您刪除了全部Puntaje,它在deleted列表中添加了全部Puntaje。現在,當你調用merge,我* TS確實不夠聰明 *和它想通了,它應該被插入,而不是更新,並在insert列表中。當你調用commit時,它會首先嚐試從插入列表中插入對象,並且正如你所期望的那樣,它會失敗,因爲舊的對象還沒有被刪除。

第二個例子的區別僅在於,強制插入前首先刪除對象,因此不會失敗。

我相信,即使您使用flush代替commit,也不會失敗。

希望這有助於你瞭解失敗背後的原因。

+0

它也會因爲同樣的問題而失敗! – user1777914

+0

另外,我試圖插入的元組擁有所有相同的ID(在Cliente方面),但是新的Puntaje,所以即使所有舊的元素都被刪除,只有第一個合併是插入,其餘的是更新,爲什麼是不是JPA足夠聰明,然後做不完全相同的刪除操作? 我忘了提及,這發生在表完全是空的時候(所以刪除實際上什麼都不做) – user1777914

+0

@ user1777914刪除後是否放入了flush?你可以做一個選擇後刪除,以確保它真的沖洗? –