2016-05-30 79 views
2

我在我的数据库中的这些(简体)表休眠例外:重复的条目键“主要”

enter image description here

我与这些(简体)两个类映射表

公司

@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 
} 

我使用的员工SortedSet/TreeSetCompany定义为获得按名称排序的员工。

当我坚持对象时会出现问题。我读过你必须在双方建立关系。在坚持公司之前,我将公司中的员工和公司中的员工设置在员工中。当我尝试执行坚持时,我将获得以下例外

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.access$100(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 

这是生成该异常的简化代码。 [编辑者@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(); 
     } 
    } 

这些是由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 (?, ?) 

如果我评论第26,28,30和32行(上面标记),相同的代码完美地工作。但我想知道为什么会生成这个异常。为什么重复键?

在此先感谢。

+0

尝试添加坚持(c);在Employee e1之前.. –

+0

注意:我不认为在finally块中调用tx.commit()是个好主意 –

+0

@NicolasFilotto得到相同的异常。为什么在finally块中放置提交不是一个好主意? – RubioRic

回答

4

重复是由您的公司 - 员工关系在两个实体中重复引起的。每个都被设置为单向1:M(一边出于某种原因使用1:1),并且两者都使用相同的连接表,当JPA去插入两边的条目时导致重复。

解决方法是将一方标记为'mappedby'另一方。

@OneToMany(mappedBy="company", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) 
@OrderBy("name ASC") 
private SortedSet<Employee> employees = new TreeSet<Employee>(); 
+0

我虽然Hibernate可以检测并避免插入链接表中的重复。我不知道我不能同时标记单向。感谢你的回答。 – RubioRic