2012-11-12 61 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?你可以做一个选择后删除,以确保它真的冲洗? –