在我的系统中经过几个小时缩小这个案例后,我发现了一些看起来像Hibernate中的bug的东西(对我来说仍然很难相信)。所以我做了一个单独的迷你项目,以排除系统单独的所有可能的副作用。这个bug仍然存在。
问题是在数据库Employee表中我有这个:
Id | IdKiP | First Name | Last Name |
-------------------------------------
32 | 32 | ELLE | SZARAW |
48 | 32 | ELLE | SZARAW |
70 | 32 | ELLE | SZARAW |
78 | 32 | ELLE | SZARAW |
94 | 32 | ELLE | SZARAW |
在缺勤表中:
Id | employee_idKiP | absenceNoDays |
-------------------------------------
1 | 32 | 3 |
2 | 32 | 3 |
3 | 32 | 4 |
4 | 32 | 5 |
5 | 32 | 4 |
如果您必须知道:它在许多版本中都是相同的员工 - 但我认为这超出了问题的范围。
我有简单的实体来映射这个表。最重要的是,Absences与Employee的ManyToOne关系,但不是员工ID,而是其idKiP Employee absences collection中描述的内容:
@OneToMany()
@JoinColumn(name = "PRACOWNIK_ID", referencedColumnName = "idKiP")
protected List<Absence> employeeAbsences = new ArrayList<Absence>();
问题:一旦我查询idKiP = 32的员工,我的持久性上下文似乎就被打破了。在下一次合并(或刷新)中,我得到错误&#34; org.hibernate.HibernateException:找到对集合的共享引用&#34; - 这是正确的,因为我可以在调试器中看到所有员工都有相同的参考/指向缺席的集合 - 但是那些由Hibernate创建的集合 - 所以它看起来像HB(检查了许多HB版本,即3.5.4,4.2。 8,5.2.6)错误,我不知道如何处理它。
我做错了什么?
链接到Maven中的mini-projekt:https://drive.google.com/open?id=1u2aMVsFJDbkswhhm3E-wCpJZBULK-LQG
完整的代码就像休闲:
我们在项目中有两个实体 - 员工:
package com.javawebtutor;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Entity
@javax.persistence.Table(name = "PLC_Pracownik")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "H_PLC_IDPRACOWNIK_GEN", sequenceName = "PLC_IDPRACOWNIK_GEN", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "H_PLC_IDPRACOWNIK_GEN")
@Column(name = "IDPRACOWNIK")
protected Long id;
public static final String PROP_IDPRACOWNIK = "id";
@Column(name = "IDKIP")
private Long idKiP;
public static final String PROP_IDKIP = "idKiP";
public Long getIdKiP() {
return idKiP;
}
public void setIdKiP(Long idKiP) {
this.idKiP = idKiP;
}
@Column(name = "nazwisko")
protected String lastName;
public static final String PROP_LASTNAME = "lastName";
@Column(name ="imie")
protected String firstName;
public static final String PROP_FIRSTNAME = "firstName";
@OneToMany()
@JoinColumn(name = "PRACOWNIK_ID", referencedColumnName = "idKiP")
protected List<Absence> employeeAbsences = new ArrayList<Absence>();
public static final String PROP_EMPLOYEEABSENCES = "employeeAbsences";
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public int hashCode() {
int hash = 0;
hash += (this.id != null ? this.id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Employee)) {
return false;
}
Employee other = (Employee) object;
if ((this.getId() == null && other.getId() != null) || (this.getId() != null && !this.getId().equals(other.getId())))
return false;
return true;
}
@Override
public String toString() {
String s = "";
s = getLastName() != null ? getLastName() : "???";
s += " " + getFirstName()+ " Id :"+getId()+" ; idKiP: "+idKiP;
return s;
}
public String getLastName() {
return lastName;
}
public void setLastName(String val) {
this.lastName = val;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String val) {
this.firstName = val;
}
public List<Absence> getEmployeeAbsences() {
return employeeAbsences;
}
public void setEmployeeAbsences(List<Absence> employeeAbsences) {
this.employeeAbsences = employeeAbsences;
}
}
在员工实体中,关键是,referencedColumnName =&#34; idKiP&#34; - 这意味着我想通过 idKiP 来接受/加入Absences不是&#34;主要&#34; id - 从数据库的角度来看,我需要的是什么。
缺失:
package com.javawebtutor;
import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
@Entity
@javax.persistence.Table(name = "PLC_Absencja")
public class Absence implements Serializable {
private static final long serialVersionUID = 1L;
@SequenceGenerator(name = "H_PLC_IDABSENCJA_GEN", sequenceName = "PLC_IDABSENCJA_GEN", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "H_PLC_IDABSENCJA_GEN")
@Id
@Column(name = "IDABSENCJA")
private Long id;
public static final String PROP_ID = "id";
@Column(name="PRACOWNIK_ID", nullable=false)
protected Long employee_idKiP;
public static final String PROP_EMPLOYEE_IDKIP = "pracownik_"+"idKiP";
@Column(name="dniNieobecnosci", precision = 18, scale = 4)
private BigDecimal absenceNoDays;
public static final String PROP_ABSENCENODAYS = "absenceNoDays";
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getAbsenceNoDays() {
return absenceNoDays;
}
public void setAbsenceNoDays(BigDecimal absenceNoDays) {
this.absenceNoDays = absenceNoDays;
}
public Long getEmployee_idKiP() {
return employee_idKiP;
}
public void setEmployee_idKiP(Long employee_idKiP) {
Long old = this.employee_idKiP;
this.employee_idKiP = employee_idKiP;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="PlacePU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.javawebtutor.Absence</class>
<class>com.javawebtutor.Employee</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.bytecode.use_reflection_optimizer" value="false"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
<property name="hibernate.connection.autocommit" value="true"/>
<property name="hibernate.connection.driver_class" value="org.firebirdsql.jdbc.FBDriver"/>
<property name="hibernate.connection.password" value="masterkey"/>
<property name="hibernate.connection.url" value="jdbc:firebirdsql://127.0.0.1//Users/pedropuchalski/Documents/praca/Projekt17.50/InforSystem/WorkingDir/db/TEST_1"/>
<property name="hibernate.connection.username" value="sysdba"/>
<property name="hibernate.current_session_context_class" value="thread"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.FirebirdDialect"/>
<property name="hibernate.format_sql" value="false"/>
<property name="hibernate.generate_statistics" value="false"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.statement_cache.size" value="0"/>
<!-- property name="hibernate.hbm2ddl.auto" value="update"/-->
</properties>
</persistence-unit>
</persistence>
测试代码:
package com.javawebtutor;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.List;
public class JpaTest {
private static EntityManager em;
public static void main(String[] args) {
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("PlacePU");
EntityManager entityManager = emf.createEntityManager();
try {
Employee prac = (Employee) entityManager.find(Employee.class, 94L);
String akthql = "from " + Employee.class.getName();
akthql += " where " + Employee.PROP_IDKIP + "=" + prac.getIdKiP();
List<Employee> aktl = entityManager.createQuery(akthql).getResultList();
for (Employee px : aktl) {
System.out.println(px);
System.out.println(System.identityHashCode(px.getEmployeeAbsences()));
}
entityManager.getTransaction().begin();
entityManager.merge(prac);
entityManager.getTransaction().commit();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
entityManager.close();
emf.close();
System.exit(0);
}
}
}
打印的内容(错误之前) - 并且在数据库方面是正确的:
SZARYK ELLE Id :32 ; idKiP: 32
1907604549
SZARYK ELLE Id :48 ; idKiP: 32
1907604549
SZARYK ELLE Id :70 ; idKiP: 32
1907604549
SZARYK ELLE Id :78 ; idKiP: 32
1907604549
SZARYK ELLE Id :94 ; idKiP: 32
1907604549
最后我得到了错误:
lut 22, 2018 11:25:42 AM org.hibernate.internal.ExceptionMapperStandardImpl mapManagedFlushFailure
ERROR: HHH000346: Error during managed flush [org.hibernate.HibernateException: Found shared references to a collection: com.javawebtutor.Employee.employeeAbsences]
javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:75)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:71)
at com.javawebtutor.JpaTest.main(JpaTest.java:34)
Caused by: javax.persistence.PersistenceException: org.hibernate.HibernateException: Found shared references to a collection: com.javawebtutor.Employee.employeeAbsences
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:147)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:56)
... 2 more
Caused by: org.hibernate.HibernateException: Found shared references to a collection: com.javawebtutor.Employee.employeeAbsences
at org.hibernate.engine.internal.Collections.processReachableCollection(Collections.java:182)
at org.hibernate.event.internal.FlushVisitor.processCollection(FlushVisitor.java:42)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:155)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:38)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1428)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:484)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3190)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2404)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
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:220)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)
... 1 more