Java 删除查询失败后的JPA合并

Java 删除查询失败后的JPA合并,java,sql,jpa,h2,Java,Sql,Jpa,H2,请分析以下两个代码,并告诉我为什么第一个在执行提交时失败,主键违反,而第二个没有 提交时失败的代码: try{ Query q = em.createQuery("DELETE FROM Puntaje"); q.executeUpdate(); //em.getTransaction().commit(); //em.getTransaction().begin(); Iterator it = l.itera

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

提交时失败的代码:

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");
    }
唯一的区别是第一个查询不提交delete查询,而是在最后一起提交。 客户和Puntaje是1:N双向关系,cascade=ALL。 所有插入的Cliente实例都有相同的ID,但是merge应该足够聪明,可以在第一个实例被持久化后更新而不是insert,但是在第一个示例中这似乎失败了,我找不到任何解释。 我也在使用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;
@实体
公共类Puntaje实现了可比较的、可序列化的{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
私人整数合计;
@多通(cascade=CascadeType.ALL,可选=false)
@JoinColumn(name=“NICK”)
私人客户;
@实体
公共类客户机实现了可序列化{
@身份证
私人字符串尼克;
@OneToMany(cascade=CascadeType.ALL,mappedBy=“cliente”)
私人名单puntajes;

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

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

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

我确信,即使您使用
flush
代替
commit
,它也不会失败


希望这有助于您理解失败背后的原因。

您是否收到“Cliente”或“Puntaje”的主键冲突?您是否可以发布stacktrace?是的,主键异常,似乎只插入一次然后更新所有其余内容不够聪明,它会在每次合并时尝试插入,这很奇怪,因为delete会这样做没有什么,只是失败了。flush也失败了!而且,我尝试插入的元组具有相同的ID(在客户端)但是新的Puntaje,所以即使在所有旧的被删除之后,只有第一次合并是一个插入,其余的是一个更新,为什么JPA没有足够聪明,在不提交删除操作的情况下执行完全相同的操作呢?我忘了提到,当表完全为空时会发生这种情况(所以删除实际上什么都不做)@user1777914您是否在删除后刷新了?您是否可以在删除后进行选择以确保它确实刷新了?是的,我这样做了,选择将不会返回任何结果,因为表一开始是空的。@user1777914:我错过了这部分。这是因为您正在使用query
delete FROM Puntaje
查询来删除所有
Puntaje
。i exp当你删除某些对象时,我提出了这个概念。我认为JPA做了一些类似的事情,但对这种查询操作没有做更多的事情。而且我相信这会导致
flush
不起作用,因为delete并不是围绕某个特定对象的,而是一个在
commit
生效的通用查询。