0

请分析以下两个代码,并告诉我为什么第一个在提交时因违反主键而失败,而第二个则没有。

提交失败的代码:

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 是 1:N 双向关系,cascade = ALL。并且所有插入的 Cliente 实例都具有相同的 ID,但是合并应该足够聪明,可以在第一个持久化后更新而不是插入,但这在第一个示例中似乎失败了,我找不到任何解释。我也使用 H2 嵌入式数据库。

我还想补充一点,如果已经插入了 Cliente 值,则第一个代码可以正常工作,当表实际上为空时,这将失败,因此 delete 实际上什么也不做。

这是我得到的错误:

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(Clases.Cliente@21cd5b08)
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(Clases.Cliente@21cd5b08

)

这些是表格:

@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;
4

1 回答 1

2

当您对对象执行操作时,所有操作仅记录在缓存中。JPA 将准备要插入、更新和删除的所有对象的内部列表。flush调用或时将一起刷新commit

现在举第一个例子。您删除了 all Puntaje,这会将所有内容添加Puntajedeleted列表中。现在,当您调用 时merge,我* ts 确实足够聪明* 并且它发现它应该被插入而不是更新和添加到insert列表中。当您调用 commit 时,它首先尝试从插入列表中插入对象,正如您所料,它会失败,因为旧对象尚未删除。

第二个示例的唯一区别在于,强制您在插入之前先删除对象,因此它不会失败。

我敢肯定,即使您使用flush.commit

希望这可以帮助您了解失败背后的原因。

于 2012-11-12T06:12:47.130 回答