在不应该出现的地方找到对集合org.hibernate.HibernateException的共享引用(提供迷你项目)

时间:2018-02-22 13:37:14

标签: java hibernate jpa

在我的系统中经过几个小时缩小这个案例后,我发现了一些看起来像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

0 个答案:

没有答案