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

Posted

技术标签:

【中文标题】克服 Hibernate 中的延迟加载问题,多对多关系【英文标题】:Overcoming lazy loading issues in Hibernate, many-to-many, relationship 【发布时间】:2014-08-31 02:39:47 【问题描述】:

自学Hibernate,我有如下表结构/关系

由以下类表示...

用户

@Entity
@Table(name = "users")
public class User implements IUser<Role>, Serializable 

    @Id
    @GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)
    @SequenceGenerator(name = "user_key_seq")
    @Column(name = "key", insertable = false, updatable = false)
    private Long key;

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

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "userroles",
                    joinColumns = 
                        @JoinColumn(name = "userkey"),
                    inverseJoinColumns = 
                        @JoinColumn(name = "rolekey"))
    private Set<Role> roles = new HashSet<>(5);

    @Override
    public Set<Role> getRoles() 
        return roles;
    

    // Other setters and getters


角色

@Entity
@Table(name = "roles")
public class Role implements IRole, Serializable 

    @Id
    @GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)
    @SequenceGenerator(name = "roles_key_seq")
    @Column(name = "key", insertable = false, updatable = false)
    private Long key;

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

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name="parentroles",
                    joinColumns = @JoinColumn(name="childkey"),
                    inverseJoinColumns = @JoinColumn(name="parentkey"))
    private Set<Role> roles = new HashSet<>(5);

    // Other setters and getters


我遇到的问题是……

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)

现在,我知道我可以将 fetch 类型设置为 FetchType.EAGER,但我不想这样做,除了性能问题,我正在努力学习解决这些问题的方法;)

我想知道是否有办法编写 Hibernate 查询来满足这种关系并手动加载行(它还允许我返回 Role 的接口而不是我必须做的实现现在(允许我维持该合同)。

根据我的阅读,我似乎需要为UserRoles 构造一个Entity。并不是说我反对这个解决方案,但我很好奇是否有办法绕过它。

roles出现在其他一些关系中,所以没办法和父表形成直接关系(就是我不能把父表的key放到@987654333直接@table,另外users可以有多个roles)

我想到的另一个解决方案是编写一个存储过程来为我做这件事。虽然这是一个可行的解决方案,但我并不在意,但它确实使将应用程序迁移到另一个数据库变得更加困难,而不是阻碍,但我试图牢记这些想法。

【问题讨论】:

hibernate: LazyInitializationException: could not initialize proxy的可能重复 我不确定您是否可以将其作为接口的实例而不是类来检索。 @LuiggiMendoza 我想要做的是返回接口的Set,其中包含实现,我尝试这样做的原因是我的程序上面有一个接口层对话,以便加载数据的实际机制对程序层隐藏,所以如果我想更改“数据层”,我可以,就是这样;) @Zeus 是的,我已经读过,正如我所说,我知道我可以更改 fetch 类型,但如果我能提供帮助,我宁愿不这样做,我会想知道这个特定问题的替代解决方案。这只是一个简单的例子,我有更复杂的关系,如果不是更多的子记录,最终可能会加载 100 个;) 【参考方案1】:

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

【讨论】:

【参考方案2】:

如果您使用的是 Hibernate 4.1.6+,那么可以通过使用 hibernate.properties 中的 hibernate.enable_lazy_load_no_trans 属性来处理这些惰性关联问题。

更多请参考:https://***.com/a/11913404/286588

【讨论】:

使用它并不能真正解决问题,并且可能会在以后导致更多问题,因为这可能导致 Hibernate 为一个简单的项目加载大量数据。这就是存在延迟加载的原因。【参考方案3】:

如果您想加载用户及其角色,但仍保持关联惰性,请使用包含 left join fetch 的 HQL 查询:

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

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

【讨论】:

我如何定义角色和用户之间的约束/关系,或者无关紧要还是已经由注释定义? 你定义的关联没问题。您可以定义一个反向关联(即 role.users),但我想它不会真正有用。至少不是执行上面的查询。 好的,Session 关闭后,您将如何完成此操作? 你不能。这就是惰性获取的工作原理:它需要打开一个会话才能执行填充关联所需的 SQL 查询。如果在获取用户时必须获取角色,那么用于获取用户的事务也必须获取角色。 好的,这给了我一些想法,同时我也能够一瘸一拐地拼凑出一些东西。干杯

以上是关于克服 Hibernate 中的延迟加载问题,多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

当对集合进行 get 调用时,Hibernate 会删除延迟加载的多对多集合

解决hibernate中的懒加载(延迟加载)问题

hibernate的延迟加载

Hibernate-延迟加载和立即加载

Hibernate检索策略之延迟加载和立即加载

如何在休眠/弹簧中更新多对多集合(延迟加载)?