更新实体时发生java.sql.SQLIntegrityConstraintViolationException
我是JPA新手,我遇到了以下问题,可能是因为对级联和关联的理解不够? 我有两个实体,它们是双向的一对一-多对一关联:更新实体时发生java.sql.SQLIntegrityConstraintViolationException,java,jpa,Java,Jpa,我是JPA新手,我遇到了以下问题,可能是因为对级联和关联的理解不够? 我有两个实体,它们是双向的一对一-多对一关联: @Entity public class TestRun implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
@Entity
public class TestRun implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
public Long getId() {
return id;
}
public TestRun(){
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne(optional=false, cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Test performedTest;
public Test getPerformedTest() {
return performedTest;
}
public void setPerformedTest(Test performedTest) {
this.performedTest = performedTest;
}
.....
@Override
public boolean equals(Object object) {
if (!(object instanceof TestRun)) {
return false;
}
TestRun other = (TestRun) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "TestRun[ id=" + id + " ]";
}
}
以及:
当createTestRun处理新的测试(插入)时,测试对象与测试运行一样被正确地持久化。但是当测试已经存在时,JPA(在我的例子中是EclipseLink)无论如何都会尝试执行插入:
....
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL110705102925930' defined on 'TEST'.
Error Code: -1
Call: INSERT INTO TEST (ID, NAME) VALUES (?, ?)
幕后发生了什么?这个问题是否与测试的AppearSonterRuns属性有关?为什么JPA不理解DB中已经存在测试(毕竟,id属性是在find操作期间设置的,equals()使用此值来决定两个测试是否相等..)
非常感谢你的帮助!:)
PS:你知道有一本很好的教程/书详细解释了这些概念吗?首先,你应该检查整个
createTestRun
方法(找到测试,必要时创建测试,然后创建TestRun
实例并将其持久化)是否在单个事务中运行
您的newestrun方法应该初始化关系的两侧,这是双向的。开发人员有责任保持实体图的一致性。因此,它应该做到:
public static TestRun newTestRun(Test test){
TestRun run = new TestRun();
run.setPerformedTest(test);
test.getAppearsOnTestRuns().add(run);
return run;
}
你能给我们看看EntityFactory.newTestRun(testPerformed)的代码吗?嗨!我刚做完!:)我认为:从DB中检索到的Test-s在ejb.find()返回后被解除跟踪,因此应该从同一事务中手动合并,然后保存新的TestRun对象?它们不应该分离。整个createTestRun方法应该在单个事务中执行。事务应该用于原子功能更改,而不是用于原子查询或数据库更新。问题是,我必须在不同的时间构建TestRun对象。。假设createTestRun(字符串名)返回它创建的TestRun对象,并且第二次,另一个方法调用ejb.persist(TestRun)。。我是否必须在EJB公共void persist(TestRun TestRun){TestRun.setPerformedTest(em.merge(TestRun.getPerformedTest());em.persist(TestRun);}中显式执行://Method,还是有更好/更简单的方法?谢谢我不明白。另一个线程将有另一个TestRun实例。有什么问题吗?您还没有显示EntityFactory.newTestRun(testPerformed)的代码。
....
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL110705102925930' defined on 'TEST'.
Error Code: -1
Call: INSERT INTO TEST (ID, NAME) VALUES (?, ?)
public static TestRun newTestRun(Test test){
TestRun run = new TestRun();
run.setPerformedTest(test);
test.getAppearsOnTestRuns().add(run);
return run;
}