在Hibernate中的@ManyToMany映射注释中,出现了“无法初始化代理 - 无会话错误:无法懒加载角色的集合”。
在Hibernate中的@ManyToMany映射注释中,出现了“无法初始化代理 - 无会话错误:无法懒加载角色的集合”。
我是Java服务器端的新手,用于创建JSON API,我在Hibernate中使用ManytoMany映射来连接两个表。我有两个类,一个是Product.class,另一个是Offers.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
//这里是我的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;
//这里是我的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
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好还是坏,有人可以解释一下吗?
这个问题的出现是因为在Hibernate的@ManyToMany映射注解中,出现了"failed to lazily initialize a collection of role: could not initialize proxy - no Session"错误。这个错误的原因是在使用LAZY加载模式时,事务在初始获取数据后被关闭,而当调用getOffers()方法时,Hibernate试图建立数据库连接,但由于连接/会话已关闭,所以导致了错误的发生。
解决这个问题的方法是可以将加载模式从LAZY改为EAGER。当使用EAGER加载模式时,JPA会在获取数据时同时从关联表中获取对应的数据,避免了在调用getOffers()时再次建立数据库连接的问题。这样可以确保数据的完整性,并避免了"failed to lazily initialize a collection of role: could not initialize proxy - no Session"错误的发生。
下面是一段示例代码,演示了如何使用EAGER加载模式解决这个问题:
@Entity @Table(name = "product") public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String code; // 使用EAGER加载模式 @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "product_offer", joinColumns = @JoinColumn(name = "product_id"), inverseJoinColumns = @JoinColumn(name = "offer_id")) private Setoffers; // 省略其他属性和方法 } @Entity @Table(name = "offer") public class Offer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // 省略其他属性和方法 }
在上面的示例代码中,我们将Product类中的加载模式从LAZY改为了EAGER。这样在获取Product对象时,它的offers属性会立即从关联表中获取对应的数据,避免了在调用getOffers()时再次建立数据库连接的问题。
总结起来,当出现"failed to lazily initialize a collection of role: could not initialize proxy - no Session"错误时,可以考虑将加载模式从LAZY改为EAGER,以确保数据的完整性并避免错误的发生。
原因:当使用@ManyToMany注解进行映射时,在Hibernate中出现"failed to lazily initialize a collection of role: could not initialize proxy - no Session"错误是因为默认情况下,Hibernate使用的是延迟加载(Lazy Loading)策略。这意味着在访问关联的集合属性时,Hibernate将尝试延迟加载(只在需要时加载)该集合,并且在加载该集合之前已经关闭了与数据库的会话(Session),因此无法初始化代理对象。
解决方法:可以采用以下两种方法来解决这个问题:
1. 使用EAGER加载策略:将@ManyToMany注解上的fetch属性设置为FetchType.EAGER,这将告诉Hibernate始终在加载实体时立即获取关联的集合属性。这样可以避免延迟加载的问题,但可能会导致性能问题,特别是当关联的集合非常大时。
@ManyToMany(fetch = FetchType.EAGER)
2. 在需要访问关联的集合属性时,手动加载该集合:在访问关联的集合属性时,使用Hibernate的initialize()方法手动加载该集合。这将强制Hibernate初始化代理对象并加载关联的集合。在使用该方法之前,确保会话(Session)仍然处于打开状态。
Hibernate.initialize(entity.getCollectionProperty());
通过以上两种方法,可以解决"failed to lazily initialize a collection of role: could not initialize proxy - no Session"错误,并正确加载关联的集合属性。
failed to lazily initialize a collection of role: could not initialize proxy - no Session
错误的出现原因是调用了一个懒加载的集合属性,但是没有激活Hibernate会话。而解决方法是通过调用Hibernate.initialize()
方法来手动初始化懒加载的关系。
在Hibernate中,关系可以使用EAGER
或LAZY
来进行标记。当关系被标记为EAGER
时,意味着在获取父实体时,所有的关联数据都会从数据库中一次性获取。而LAZY
关系,只会在最初获取父实体的数据时进行加载,关联的子实体数据会在第一次访问它的属性时,使用单独的SQL语句进行获取。但是,这需要在Hibernate会话处于活动状态时才能正常工作。否则,就会出现failed to lazily initialize a collection
的异常。
对于@ManyToMany
映射,LAZY
是默认值,这是有道理的,因为Many
可能意味着很多的数据,你可能并不需要全部获取。因此,通常最好将其保持为LAZY
,在需要的时候在服务中获取数据。Hibernate提供了一个初始化懒加载关系的工具方法Hibernate.initialize()
,可以手动初始化懒加载的关系。
但是,正如开头所说,具体使用哪种加载方式取决于具体的使用场景,最好了解EAGER
和LAZY
的所有影响,以便可以做出适当的决策。