Java 克服Hibernate多对多关系中的延迟加载问题

Java 克服Hibernate多对多关系中的延迟加载问题,java,hibernate,Java,Hibernate,在自学Hibernate时,我有以下表格结构/关系 它由以下类表示 使用者 @实体 @表(name=“users”) 公共类用户实现IUser,可序列化{ @身份证 @GeneratedValue(策略=javax.persistence.GenerationType.IDENTITY) @SequenceGenerator(name=“user\u key\u seq”) @列(name=“key”,insertable=false,updateable=false) 私钥; @列(name

在自学Hibernate时,我有以下表格结构/关系

它由以下类表示

使用者
@实体
@表(name=“users”)
公共类用户实现IUser,可序列化{
@身份证
@GeneratedValue(策略=javax.persistence.GenerationType.IDENTITY)
@SequenceGenerator(name=“user\u key\u seq”)
@列(name=“key”,insertable=false,updateable=false)
私钥;
@列(name=“name”)
私有字符串名称;
@ManyToMany(cascade={CascadeType.ALL})
@JoinTable(name=“userroles”,
joinColumns={
@JoinColumn(name=“userkey”)},
反向连接列={
@JoinColumn(name=“rolekey”)}
私有集角色=新哈希集(5);
@凌驾
公共集getRoles(){
返回角色;
}
//其他二传手和接球手
}
角色
@实体
@表(name=“roles”)
公共类角色实现IRole,可序列化{
@身份证
@GeneratedValue(策略=javax.persistence.GenerationType.IDENTITY)
@SequenceGenerator(name=“roles\u key\u seq”)
@列(name=“key”,insertable=false,updateable=false)
私钥;
@列(name=“name”)
私有字符串名称;
@ManyToMany(cascade={CascadeType.ALL})
@JoinTable(name=“parentroles”,
joinColumns={@JoinColumn(name=“childkey”)},
inverseJoinColumns={@JoinColumn(name=“parentkey”)}
私有集角色=新哈希集(5);
//其他二传手和接球手
}
我遇到的问题是

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.kaizen.chishiki.core.data.User.roles, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
    at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
    at og.kaizen.chishiki.core.testdatacore.Main.<init>(Main.java:37)
    at og.kaizen.chishiki.core.testdatacore.Main.main(Main.java:25)
org.hibernate.LazyInitializationException:未能延迟初始化角色集合:org.kaizen.chishiki.core.data.User.roles,无法初始化代理-无会话
位于org.hibernate.collection.internal.AbstractPersistentCollection.ThrowlazyiInitializationException(AbstractPersistentCollection.java:575)
位于org.hibernate.collection.internal.AbstractPersistentCollection.WithTemporarySessionIneed(AbstractPersistentCollection.java:214)
位于org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
位于org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
位于org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
位于og.kaizen.chishiki.core.testdatacore.Main.(Main.java:37)
位于og.kaizen.chishiki.core.testdatacore.Main.Main(Main.java:25)
现在,我知道我可以将
fetch
类型设置为
FetchType.EAGER
,但我不希望这样做,除了性能方面的考虑,我正在努力学习解决这些问题的方法;)

我想知道是否有一种方法可以编写一个Hibernate查询来满足这种关系并手动加载行(它还允许我返回
Role
接口,而不是像我现在必须做的那样返回实现(允许我维护该契约))

从我读到的内容来看,似乎我需要为
用户角色
构建一个
实体
。并不是说我反对这个解决方案,但我很好奇是否有办法绕过它

角色
出现在许多其他关系中,因此它无法与父表形成直接关系(也就是说,我不能将父表的
直接放在
角色
表中,此外,
用户
可以有多个
角色


我想到的另一个解决方案是编写一个存储过程来为我完成它。虽然这是一个可行的解决方案,但我不打算这么做,它确实会使将应用程序迁移到另一个数据库变得更加困难,这不是一个阻碍,但我正试图记住这些想法。

如果您想加载用户的角色,但仍然保持关联的惰性,请使用包含
左连接获取的HQL查询。

select u from User u left join fetch u.roles where ...

如果您有一个用户,并且希望在关闭会话之前确保其角色集合已初始化,请调用
Hibernate.initialize(User.getRoles())

如果您使用的是Hibernate 4.1.6+,则可以使用Hibernate.properties中的Hibernate.enable\u lazy\u load\u no\u trans属性来处理这些惰性关联问题


有关更多信息,请参阅:

我通过将控制器中的方法注释为事务性方法解决了此问题。由于延迟加载基本上返回未来对象的列表,该方法需要是事务性的。

的可能重复项我不确定是否可以将其作为接口实例而不是类检索。@LuiggiMendoza我要做的是返回接口的
集,其中包含实现,这是我尝试执行此操作的原因,我在上面有一个接口层,我的程序与之对话,因此加载数据的实际机制对程序层是隐藏的,所以如果我想更改“数据层”,我可以,仅此而已;)@宙斯是的,我已经读到了,正如我所说的,我知道我可以更改
获取
类型,但如果我能帮助它,我宁愿不这样做,我想知道这个特定问题的替代解决方案。这只是一个简单的例子,我有更复杂的关系,如果没有更多的子记录,可能会加载100条记录;)我如何定义角色和用户之间的约束/关系,或者这无关紧要,或者已经由注释定义了?您定义的关联是确定的。您可以定义一个反向关联(即role.users),但我想它不会真的有用。至少不能执行上面的查询。好吧,在
会话
关闭后,您将如何完成此操作?您不能。这就是延迟抓取的工作原理:它需要打开一个会话才能执行填充关联所需的SQL查询。如果
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.kaizen.chishiki.core.data.User.roles, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
    at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
    at og.kaizen.chishiki.core.testdatacore.Main.<init>(Main.java:37)
    at og.kaizen.chishiki.core.testdatacore.Main.main(Main.java:25)
select u from User u left join fetch u.roles where ...