java 休眠异常:键“PRIMARY”的重复条目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37528962/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate exception: Duplicate entry for key 'PRIMARY'
提问by RubioRic
I've these (simplified) tables in my database
我的数据库中有这些(简化的)表
I've mapped the tables with these (simplified) two classes
我已经用这些(简化的)两个类映射了表
COMPANY
公司
@Entity
public class Company {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(name="company_employee",
joinColumns={@JoinColumn(name="company_id")},
inverseJoinColumns={@JoinColumn(name="employee_id")})
@OrderBy("name ASC")
private SortedSet<Employee> employees = new TreeSet<Employee>();
// contructors + getters + setters
}
EMPLOYEE
员工
@Entity
public class Employee implements Comparable<Employee> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(fetch = FetchType.LAZY, optional = true)
@JoinTable(name="company_employee",
joinColumns={@JoinColumn(name="employee_id")},
inverseJoinColumns={@JoinColumn(name="company_id")}
)
private Company company;
@Override
public int compareTo(Employee anotherEmployee) {
return this.name.compareTo(anotherEmployee.name);
}
// contructors + getters + setters + equals + hashcode
}
I'm using a SortedSet/TreeSet
in employees defined in Company
to obtain the employees sorted by name.
我使用SortedSet/TreeSet
in 定义Company
的员工来获取按名称排序的员工。
The problem arises when I persist the objects. I've read that you must establish the relation in both sides. I set the employee in company and the company in the employee before persisting the company. When I try to execute the persist, I'm obtaining the following exception
当我坚持对象时出现问题。我读过你必须建立双方的关系。在坚持公司之前,我将员工设置为公司,将公司设置为员工。当我尝试执行持久化时,我收到以下异常
Exception in thread "main" javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86)
at es.rubioric.hibernate.MainTest.main(MainTest.java:43)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:67)
... 1 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1314)
at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:50)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:447)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:333)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:335)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1224)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:464)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2890)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2266)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access0(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:230)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61)
... 1 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '32-80' for key 'PRIMARY'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
at com.mysql.jdbc.Util.getInstance(Util.java:381)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1015)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3558)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3490)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2109)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2643)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2077)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2362)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2280)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2265)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
... 18 more
This is a simplified code that generates that exception. [EDITED commit location after comment by @NicolasFilotto]
这是生成该异常的简化代码。[在@NicolasFilotto 发表评论后编辑提交位置]
public static void main(String[] args) throws ParseException {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("TestDB");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Company c = new Company("Nike");
Employee e1 = new Employee("Anthony");
e1.setCompany(c); // line 26
Employee e2 = new Employee("Zenobia");
e2.setCompany(c); // line 28
Employee e3 = new Employee("Chuck");
e3.setCompany(c); // line 30
Employee e4 = new Employee("Bernard");
e4.setCompany(c); // line 32
c.getEmployees().add(e1);
c.getEmployees().add(e2);
c.getEmployees().add(e3);
c.getEmployees().add(e4);
em.persist(c);
tx.commit();
} finally {
em.close();
}
}
These are the SQL sentences internally executed by Hibernate.
这些是 Hibernate 内部执行的 SQL 语句。
Hibernate: insert into Company (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into company_employee (company_id, employee_id) values (?, ?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into company_employee (company_id, employee_id) values (?, ?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into company_employee (company_id, employee_id) values (?, ?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into company_employee (company_id, employee_id) values (?, ?)
Hibernate: insert into company_employee (company_id, employee_id) values (?, ?)
The same code works perfectly if I comment lines 26, 28, 30 and 32 (marked above). But I want to know why is that exception being generated. Why the duplicated key?
如果我注释第 26、28、30 和 32 行(如上标记),则相同的代码可以完美运行。但我想知道为什么会产生异常。为什么是重复的密钥?
Thanks in advance.
提前致谢。
回答by Chris
The duplicates are caused by your company-employee relationship being duplicated in both entities. Each has been setup as a unidirectional 1:M (one side is using a 1:1 for some reason), and both are using the same join table, causing duplicates when JPA goes to insert entries for both sides.
重复是由您的公司-员工关系在两个实体中重复造成的。每个都设置为单向 1:M(一侧出于某种原因使用 1:1),并且两者都使用相同的连接表,当 JPA 为双方插入条目时会导致重复。
The solution is to mark one side as 'mappedby' the other.
解决方案是将一侧标记为“mappedby”另一侧。
@OneToMany( mappedBy="company", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@OrderBy("name ASC")
private SortedSet<Employee> employees = new TreeSet<Employee>();