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
生效的通用查询。