简体   繁体   English

使用Hibernate / JPA / Spring进行Java延迟加载

[英]Java Lazy Loading with Hibernate/JPA/Spring

I'm having an issue with converting an application to separate REST Server + Web Application rather than having a single application that handles pages + business logic. 我在将应用程序转换为单独的REST Server + Web应用程序时遇到问题,而不是拥有一个处理页面+业务逻辑的应用程序。

I'm having a problem with an org.hibernate.LazyInitializationException being thrown when Jackson is serialising the output. 我在Jackson序列化输出时抛出org.hibernate.LazyInitializationException问题。

Below is my JPA configuration and the class in question. 以下是我的JPA配置和相关的类。 I'm aware the lazy initialisation is being caused by the List member, but I don't want this to be populated in the JSON returned. 我知道延迟初始化是由List成员引起的,但是我不希望在返回的JSON中填充它。 Hence the @JsonIgnore annotation. 因此,@ JsonIgnore批注。

PersistenceConfiguration.java PersistenceConfiguration.java

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackageClasses = {ForumRepository.class})
public class PersistenceConfiguration {

@Bean
public EntityManagerFactory entityManagerFactory() {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();

    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.mypackage.forum.api.models");
    factory.setDataSource(secureDataSource());
    factory.afterPropertiesSet();

    return factory.getObject();
}

@Bean
public JpaTransactionManager transactionManager() {
    EntityManagerFactory factory = entityManagerFactory();
    return new JpaTransactionManager(factory);
}

@Bean
public HibernateExceptionTranslator exceptionTranslator() {
    return new HibernateExceptionTranslator();
}

@Bean
public DataSource secureDataSource() {
    try {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:jboss/datasources/ForumDS");
    } catch (Exception e) {
        return null;
    }
}
}

ForumGroup.java ForumGroup.java

@Entity
public class ForumGroup {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

@JsonIgnore
@OneToMany(mappedBy = "group")
private List<Forum> forums;

private String name;
private String description;

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public List<Forum> getForums() {
    return forums;
}

public void setForums(List<Forum> forums) {
    this.forums = forums;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    ForumGroup that = (ForumGroup) o;

    if (id != null ? !id.equals(that.id) : that.id != null) return false;
    if (name != null ? !name.equals(that.name) : that.name != null) return false;

    return true;
}

@Override
public int hashCode() {
    int result = id != null ? id.hashCode() : 0;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    return result;
}

@Override
public String toString() {
    return "ForumGroup{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", description='" + description + '\'' +
            '}';
}
}

I presume that I need to configure some sort of Session Manager but not sure the best way to go about doing it in JavaConfig, I've tried various methods via Google with no joy. 我以为我需要配置某种会话管理器,但是不确定在JavaConfig中执行此操作的最佳方法,我已经通过Google尝试了各种方法,但都不太高兴。

Any help would be much appreciated. 任何帮助将非常感激。

Update 更新

I've now managed to resolve this by 1) Adding the @Fetch() annotation to the relevant collections, which means that the collections get populated 2) I have stopped Entities/Models being returned as JSON objects and instead use separate DTOs 我现在设法通过以下方法解决此问题:1)在相关集合中添加@Fetch()批注,这意味着将填充集合2)我已停止将实体/模型作为JSON对象返回,而是使用单独的DTO

org.hibernate.LazyInitializationException happens when call lazy fields outside from session. 从会话外部调用惰性字段时,会发生org.hibernate.LazyInitializationException
In your situation , it's seams you select ForumGroup entities and then, outside from session you trying call entity.getForums() . 在您所处的情况下,您可以选择ForumGroup实体,然后在会话之外尝试调用entity.getForums() That's why happening LazyInitializationException . 这就是为什么发生LazyInitializationException的原因。

If you need that collection, then load them eagerly . 如果您需要该集合,请急切加载它们。 You can do that by calling: 您可以通过以下方式实现:
entity.getForums().size(); . Remember, call this inside the session 记住,在会话中调用它

You can use anotation, to to load collection EAGERLY by default : @ManyToOne(fetch = FetchType.EAGER) 您可以使用注释默认情况下自动加载EAGERLY@ManyToOne(fetch = FetchType.EAGER)

You just need to fetch the ForumGroup along with its forums list. 您只需要获取ForumGroup及其论坛列表即可。

This can be achieved with a LEFT JOIN FETCH whenever you retrieve the ForumGroup you are interested in: 每当您检索感兴趣的ForumGroup时,都可以使用LEFT JOIN FETCH来实现:

"from ForumGroup as fg " +
"left join fetch fg.forums "

You can assign a default fetching strategy, but this is a decision that will affect subsequent queries, so make sure you know the trade-offs: 您可以分配默认的提取策略,但这是一个会影响后续查询的决定,因此请确保您知道以下折衷方案:

Use a join fetch mode: 使用联接获取模式:

@JsonIgnore
@OneToMany(mappedBy = "group")
@Fetch(FetchMode.JOIN)    
private List<Forum> forums = new ArrayList<Forum>();

Or a sub-select fetch mode: 或子选择获取模式:

@JsonIgnore
@OneToMany(mappedBy = "group")
@Fetch(FetchMode.SUBSELECT)
private List<Forum> forums = new ArrayList<Forum>();

And always initialize your collections, never let them assigned to null. 并且始终初始化您的集合,永远不要让它们分配为null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM