未能延迟初始化角色集合:无法初始化代理 - Hibernate 中的 @ManyToMany 映射注释中没有会话错误? [复制]

Posted

技术标签:

【中文标题】未能延迟初始化角色集合:无法初始化代理 - Hibernate 中的 @ManyToMany 映射注释中没有会话错误? [复制]【英文标题】:failed to lazily initialize a collection of role: could not initialize proxy - no Session error in @ManyToMany mappin annotation in Hibernate? [duplicate] 【发布时间】:2015-06-14 12:19:51 【问题描述】:

您好,我是 java 服务器端创建 JSON API 的新手,我在 hibernate 中使用 ManytoMany 映射来连接两个表。我有两个类,一个是 Product.classOffers.class

Product.class

@Entity
@Table(name = "products")
public class Product 

@Column(name = "merchant_code")
private String merchant_code;

@Column(name = "branch_code")
private String branch_code;

@Column(name = "product_category_code")
private String product_category_code;

@Id @GeneratedValue
@Column(name = "product_code")
private String product_code;

@Column(name = "product_short_desc")
private String product_short_desc;

@Column(name = "product_long_desc")
private String product_long_desc;

@Column(name = "image")
private String image;

@Column(name = "price")
private String price;

@Column(name = "Active_Inactive")
private String Active_Inactive;

@ManyToMany(mappedBy = "offer_relation_code", fetch = FetchType.EAGER)
@Where(clause = "offer_type_code = 1")
private List<Offers> offer;

//here my getter setter


Offers.class

@Entity
@Table(name = "offers")
public class Offers 

@Id @GeneratedValue
@Column(name = "offer_code")
private int offer_code;

@Column(name = "offer_type_code")
private int offer_type_code;

@Column(name = "offer_relation_code")
private int offer_relation_code;

@Column(name = "branch_code")
private int branch_code;

@Column(name = "valid_from")
private String valid_from;

@Column(name = "valid_until")
private String valid_until;

@Column(name = "offer_value")
private int offer_value;

@Column(name = "offer_desc")
private String offer_desc;

//here my getter setter     


获取数据

factory = cfg.configure().addAnnotatedClass(Product.class).buildSessionFactory(registry);

    Session session = factory.openSession();
    Transaction tx = null;

    try 

        tx = session.beginTransaction();

        Criteria criteria = session.createCriteria(Product.class);
        criteria.setFetchMode("product",FetchMode.JOIN);
        Criterion merchant_code_Criterion = Restrictions.eq("merchant_code", new String(merchant_code));
        Criterion branch_code_Criterion = Restrictions.eq("branch_code", new String(branch_code));
        LogicalExpression andExp = Restrictions.and(merchant_code_Criterion,branch_code_Criterion);
        criteria.add(andExp);

        search_products = (ArrayList<Product>) criteria.list();

        tx.commit();

     catch (HibernateException e) 
        // TODO: handle exception
        if (tx != null)
            tx.rollback();
        e.printStackTrace();
     finally 
        session.close();
    

我加入offer 表和product 表就像@ManyToMany(mappedBy = "offer_relation_code", fetch = FetchType.EAGER) 我在Google 中搜索它,其中许多人说不要使用EAGER,这会导致一些问题,但是当我正在使用@ManyToMany(mappedBy = "offer_relation_code", fetch = FetchType.LAZY) 显示类似failed to lazily initialize a collection of role: could not initialize proxy - no Session 的错误。当我使用 EAGER 时,它工作正常,没有错误。使用 EAGER 是好是坏。谁能解释一下。

【问题讨论】:

我敢肯定,你可以在课堂上提供更少的字段来展示你的问题的想法。建议您在主题代码中减少源代码。 @Andremoniy 好吧,我会减少它。 【参考方案1】:

EAGERLAZY 在有用时都有用例,一般来说它们不是

当某个关系被标记为EAGER 时,这意味着当获取父实体时,该关系中的所有数据都将从数据库中获取。一个 SQL 将用于所有数据。

使用LAZY 关系,最初只获取父实体的数据。惰性关系被 Hibernate 的代理类替换,该类将在第一次访问其任何属性时使用单独的 SQL 语句获取子实体的数据。但是,必须有一个活动的 Hibernate 会话才能使其工作。在活动会话之外调用时,您会收到异常 failed to lazily initialize a collection

对于@nToMany 映射,LAZY 是默认值,这是非常有意义的,因为Many 确实可以表示很多,而且很有可能您不需要所有映射数据。因此,将其留在LAZY 并在需要的服务中获取数据通常是一个好主意。 Hibernate 有一个用于初始化惰性关系的实用方法,Hibernate.initialize(parent.getLazyChild())

但是,正如我在开头所说的,这完全取决于用例,最好知道EAGERLAZY 的所有含义,这样您就可以做出自己的决定。

【讨论】:

【参考方案2】:

先说一下你有的两个POJO。

Offer 类代表一张桌子。换句话说,它只代表一个表中的所有列,不引用任何其他表。

Product 类也只代表一个表,但是你有一个对 Offer 类的引用。

现在,如果您想获取产品代码“abc”的记录

EAGER:使用它时,您要求 JPA 使用来自产品的数据以及来自报价表的相应数据填充 POJO。

LAZY:使用它时,您要求 JPA 仅使用产品表中的数据填充 POJO。只有当您调用 getOffers() 时,才应进行另一个数据库调用以填充报价表中的相应数据。

当不经常需要引用表中的数据时,您可以使用 LAZY。优惠数据可能永远不会显示的可能性很大 (>25%)。

当引用表中的数据几乎总是需要时,您应该使用 EAGER。

对于您的错误,在您的最后一个块中,您正在调用 session.close()。当您使用 LAZY 时,事务在初始提取后关闭。当您调用 getOffers() 时,JPA 会尝试建立数据库连接 - 但由于它使用已关闭的连接/会话而失败。

【讨论】:

【参考方案3】:

EAGER 告诉 hibernate 始终获取 Many 关系上的所有组件(您问题中的所有 Offer),即使在您不需要它们的情况下也是如此。 使用 LAZY,您有责任在您真正需要的时候在交易中获取这些 Offer。

【讨论】:

以上是关于未能延迟初始化角色集合:无法初始化代理 - Hibernate 中的 @ManyToMany 映射注释中没有会话错误? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

延迟初始化:未能延迟初始化集合

休眠延迟加载不适用于 Spring Boot => 无法延迟初始化角色集合无法初始化代理 - 无会话

LazyInitializationException: 延迟初始化角色集合失败 无法初始化代理 - 没有会话

org.hibernate.LazyInitializationException:无法延迟初始化角色集合:FQPropretyName,无法初始化代理 - 无会话

无法延迟初始化角色集合:myapp.myapp.models.Contact.messages,无法初始化代理 - 没有会话

Hibernate LazyInitializationException:未能延迟初始化角色集合