【问题标题】:Hibernate- failed to lazily initialize a collection of role: beans.Language.patients, could not initialize proxy - no SessionHibernate - 无法延迟初始化角色集合:bean.Language.patients,无法初始化代理 - 无会话
【发布时间】:2017-01-30 22:02:05
【问题描述】:

我使用hibernate来创建一个rest api。我创建了一个方法来获取表中的所有项目。

public List<Language> getAllLanguages(Session session) {
        List<Language> languages=(List<Language>)session.createQuery("from Language").list();
        return languages;
}

这是我的 Language.java

public class Language  implements java.io.Serializable {


     private Integer idlanguage;
     private String language;
     private Set<Patient> patients = new HashSet<Patient>(0);

    public Language() {
    }


    public Language(String language) {
        this.language = language;
    }
    public Language(String language, Set<Patient> patients) {
       this.language = language;
       this.patients = patients;
    }

    public Integer getIdlanguage() {
        return this.idlanguage;
    }

    public void setIdlanguage(Integer idlanguage) {
        this.idlanguage = idlanguage;
    }
    public String getLanguage() {
        return this.language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }
    public Set<Patient> getPatients() {
        return this.patients;
    }

    public void setPatients(Set<Patient> patients) {
        this.patients = patients;
    }

}

这是我的 Patient.java

// Generated Sep 14, 2016 4:33:23 PM by Hibernate Tools 4.3.1


import beans.DiabetesType;
import beans.Illness;
import beans.Language;
import beans.Reminder;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * Patient generated by hbm2java
 */
public class Patient  implements java.io.Serializable {

     private Integer idpatient;
     private DiabetesType diabetesType;
     private Language language;
     private String customId;
     private String diabetesOther;
     private String firstName;
     private String lastName;
     private String userName;
     private String password;
     private Date dateCreated;
     private Date lastUpdated;
     private Set<Illness> illnesses = new HashSet<Illness>(0);
     private Set<Reminder> reminders = new HashSet<Reminder>(0);


    public Patient() {
    }

    public Patient(Integer idpatient, String password) {
        this.idpatient = idpatient;
        this.password = password;
    }    

    public Patient(DiabetesType diabetesType, Language language, String customId, String firstName, String userName, String password, Date lastUpdated) {
        this.diabetesType = diabetesType;
        this.language = language;
        this.customId = customId;
        this.firstName = firstName;
        this.userName = userName;
        this.password = password;
        this.lastUpdated = lastUpdated;
    }
    public Patient(DiabetesType diabetesType, Language language, String customId, String diabetesOther, String firstName, String lastName,  String userName, String password, Date dateCreated, Date lastUpdated, Set<Illness> illnesses, Set<Reminder> reminders) {
       this.diabetesType = diabetesType;
       this.language = language;
       this.customId = customId;
       this.diabetesOther = diabetesOther;
       this.firstName = firstName;
       this.lastName = lastName;      
       this.userName = userName;
       this.password = password;
       this.dateCreated = dateCreated;
       this.lastUpdated = lastUpdated;
       this.illnesses = illnesses;
       this.reminders = reminders;
    }

    public Integer getIdpatient() {
        return this.idpatient;
    }

    public void setIdpatient(Integer idpatient) {
        this.idpatient = idpatient;
    }
    public DiabetesType getDiabetesType() {
        return this.diabetesType;
    }

    public void setDiabetesType(DiabetesType diabetesType) {
        this.diabetesType = diabetesType;
    }
    public Language getLanguage() {
        return this.language;
    }

    public void setLanguage(Language language) {
        this.language = language;
    }
    public String getCustomId() {
        return this.customId;
    }

    public void setCustomId(String customId) {
        this.customId = customId;
    }
    public String getDiabetesOther() {
        return this.diabetesOther;
    }

    public void setDiabetesOther(String diabetesOther) {
        this.diabetesOther = diabetesOther;
    }
    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getUserName() {
        return this.userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    public Date getDateCreated() {
        return this.dateCreated;
    }

    public void setDateCreated(Date dateCreated) {
        this.dateCreated = dateCreated;
    }
    public Date getLastUpdated() {
        return this.lastUpdated;
    }

    public void setLastUpdated(Date lastUpdated) {
        this.lastUpdated = lastUpdated;
    }
    public Set<Illness> getIllnesses() {
        return this.illnesses;
    }

    public void setIllnesses(Set<Illness> illnesses) {
        this.illnesses = illnesses;
    }
    public Set<Reminder> getReminders() {
        return this.reminders;
    }

    public void setReminders(Set<Reminder> reminders) {
        this.reminders = reminders;
    }
}

重要提示:bean 和映射是通过 NetBeans 从 MySQL 数据库进行逆向工程的。调用getAllLangauges 时,我不需要获取与patient 相关的任何数据。我的language 表只有两列,idlanguagelanguagePatient 表有一个外键 language table

在 rest api 中使用此方法之前,它运行良好,没有任何异常。但是当我在rest api中使用它时,它在那里产生了复杂性。

我在这里没有使用注释。我使用休眠逆向工程向导来映射上面的实体。这是我的rest api方法。

@Path("/language")
public class LanguageJSONService {

    @GET
    @Path("/getAllLanguages")
    @Produces(MediaType.APPLICATION_JSON)
    public List<Language> getAllLanguages(){
        LanguageService languageService=new LanguageService();
        List<Language> list = languageService.getAllLanguages();
        return list;
    }
}

这是我调用方法的方式,

Client client = ClientBuilder.newClient();
List<Language> list = client.target("http://localhost:8080/simple_rest/rest")
                .path("/language/getAllLanguages")
                .request(MediaType.APPLICATION_JSON)
                .get(new GenericType<List<Language>>() {
                });

for (int i = 0; i < list.size(); i++) {
      System.out.println("Id - " + list.get(i).getIdlanguage() + " Language - " + list.get(i).getLanguage());
}

当我调用方法时,

failed to lazily initialize a collection of role: beans.Language.patients, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->beans.Language["patients"])

发生了。

有趣的是,如果我没有关闭会话,那么我会得到如下所示的输出,这完全是另外一回事,似乎它正在尝试显示其外键表及其外键表等等......

    [{"idlanguage":1,"language":"English","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":{"iddiabetesType":1,"type":"Sever","patients":
[{"idpatient":1,"diabetesType":

对这个问题有什么想法吗?

更新

我的配置文件

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="show_sql">true</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/*****</property>
    <property name="hibernate.connection.username">*****</property>
    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">3000</property>
    <property name="hibernate.c3p0.max_statements">50</property>
    <property name="hibernate.c3p0.idle_test_period">300</property>
    <property name="hibernate.c3p0.testConnectionOnCheckout">true</property>
    <property name="hibernate.c3p0.preferredTestQuery">SELECT 1</property>
    <property name="hibernate.connection.password">************</property>
    <mapping resource="beans/Reminder.hbm.xml"/>
    <mapping resource="beans/Food.hbm.xml"/>
    <mapping resource="beans/Patient.hbm.xml"/>
    <mapping resource="beans/Illness.hbm.xml"/>
    <mapping resource="beans/Language.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

语言.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 14, 2016 4:33:23 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
    <class name="beans.Language" table="language" catalog="myglukose" optimistic-lock="version">
        <id name="idlanguage" type="java.lang.Integer">
            <column name="idlanguage" />
            <generator class="identity" />
        </id>
        <property name="language" type="string">
            <column name="language" length="45" not-null="true" />
        </property>
        <set name="patients" table="patient" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="language_idlanguage" not-null="true" />
            </key>
            <one-to-many class="beans.Patient" />
        </set>
    </class>
</hibernate-mapping>

这是我的患者映射文件,

患者.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 14, 2016 4:33:23 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
    <class name="beans.Patient" table="patient" catalog="myglukose" optimistic-lock="version">
        <id name="idpatient" type="java.lang.Integer">
            <column name="idpatient" />
            <generator class="identity" />
        </id>
        <many-to-one name="diabetesType" class="beans.DiabetesType" fetch="select">
            <column name="diabetes_type_iddiabetes_type" not-null="true" />
        </many-to-one>
        <many-to-one name="language" class="beans.Language" fetch="select">
            <column name="language_idlanguage" not-null="true" />
        </many-to-one>
        <property name="customId" type="string">
            <column name="custom_id" length="45" not-null="true" />
        </property>
        <property name="diabetesOther" type="string">
            <column name="diabetes_other" length="45" />
        </property>
        <property name="firstName" type="string">
            <column name="first_name" length="100" not-null="true" />
        </property>
        <property name="lastName" type="string">
            <column name="last_name" length="100" />
        </property>        
        <property name="userName" type="string">
            <column name="user_name" length="45" not-null="true" />
        </property>
        <property name="password" type="string">
            <column name="password" length="45" not-null="true" />
        </property>
        <property name="dateCreated" type="timestamp">
            <column name="date_created" length="19" />
        </property>
        <property name="lastUpdated" type="timestamp">
            <column name="last_updated" length="19" not-null="true">
                <comment>Stores the basic information of the patient</comment>
            </column>
        </property>
        <set name="illnesses" table="illness" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="patient_idpatient" not-null="true" />
            </key>
            <one-to-many class="beans.Illness" />
        </set>
        <set name="reminders" table="reminder" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="patient_idpatient" not-null="true" />
            </key>
            <one-to-many class="beans.Reminder" />
        </set>
    </class>
</hibernate-mapping>

【问题讨论】:

  • @MWiesner:不是。您引用的链接使用的是基于注释的系统,而 OP 不是。他使用逆向工程生成了他的 bean 和映射。众所周知,注解实现方式和非注解方式存在一些差异,这也可能导致同一问题的不同原因。
  • 你在做类似 language.getPatients();
  • @Gokul:不,我没有
  • 你的配置文件?
  • @shantaram:请检查更新

标签: java mysql hibernate rest


【解决方案1】:

您的 json 转换器尝试序列化整个实体,其中包含使用每种语言的所有患者的列表。据我了解,json 中的患者列表不是预期的。所以你有三个选项(我会考虑它们的顺序):

  • 删除语言实体中患者的映射。您是否需要获得访问权限 从语言实体到病人?如果不删除此映射。
  • 在退出 tx 层之前创建一个语言 DTO,您可以在其中传输数据。这样调用服务的人永远不会得到 LazyInitException。毫不奇怪:DTO 字段总是被急切地设置。
  • 将您的 json 转换器配置为不序列化患者字段。你还没有说你正在使用哪个 json lib。其中一些为您提供了忽略某些字段的注释(例如,@JsonIgnore 用于 Jackson),其他则需要 java 配置。

要应用第一个解决方案,请以这种方式更新这些文件:

语言.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 14, 2016 4:33:23 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
    <class name="beans.Language" table="language" catalog="myglukose" optimistic-lock="version">
        <id name="idlanguage" type="java.lang.Integer">
            <column name="idlanguage" />
            <generator class="identity" />
        </id>
        <property name="language" type="string">
            <column name="language" length="45" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

语言.java

public class Language  implements java.io.Serializable {
    private Integer idlanguage;
    private String language;

    protected Language() {
    }


    public Language(String language) {
        this.language = language;
    }

    public Integer getIdlanguage() {
        return this.idlanguage;
    }

    protected void setIdlanguage(Integer idlanguage) {
        this.idlanguage = idlanguage;
    }
    public String getLanguage() {
        return this.language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }
}

我已将无参数构造函数和 setId 方法更新为 protected。您甚至可以将它们更新为 private :只有 hibernate 应该使用它们(并且它可以使用私有字段/方法)。

【讨论】:

  • 谢谢。我应该对其他表也这样做吗?
  • 这个决定应该根据具体情况来做:如果你的代码不使用一侧(特别是如果它删除了@987654328),我会将双向关联更改为单向关联@ 边)。对于配置表(如语言、国家、偏好等),了解所有使用它们的实体并不是一个很大的优势。另一方面,@*ToMany 有许多合法用途,所以不要试图将它们全部删除;)
  • 现在我有时会遇到太多连接问题。请看这个stackoverflow.com/questions/39661594/…
【解决方案2】:

当您尝试访问惰性字段时,您需要在休眠会话关闭之前完成此操作

当您退出会话上下文时,如果需要,hibernate 无法访问数据库,因此会抛出 LazyInitializationException

来自javadoc

表示访问会话上下文之外的未获取数据。例如,当在会话关闭后访问未初始化的代理或集合时。

【讨论】:

  • 请查看更新后的问题。另外,如何实现您提到的?而不是调用保存/获取等,我们必须使用Session 进行服务并完成工作?无论如何,在得到结果之前会话不会关闭。
【解决方案3】:

从目前的解释来看,我看不到你在做什么:language.getPatients();

但是,如果您正在编写 HQL 查询以从语言实体访问所有患者,那么我认为您应该使用 join 。如果与 beans.Language.patients 中的 LazyInitializationException 相关,我可以看到异常。

所以我会建议下面的代码...检查它是否对您有用..

public List<Language> getAllLanguages(Session session) {
        List<Language> languages=(List<Language>)session.createQuery("from Language as l JOIN l.patients").list();
        return languages;
}

【讨论】:

  • 你在用hbm吗?
  • 我没有使用语言来访问患者。
  • 可以分享一下你的hbm文件吗...你的pojo没问题
  • 抱歉错误。我说的。
猜你喜欢
  • 1970-01-01
  • 2016-07-06
  • 2015-07-02
  • 2018-02-25
  • 1970-01-01
  • 2016-06-04
  • 2018-11-21
  • 2014-12-23
  • 2019-05-21
相关资源
最近更新 更多