簡體   English   中英

使用Hibernate / JPA / Spring進行Java延遲加載

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

我在將應用程序轉換為單獨的REST Server + Web應用程序時遇到問題,而不是擁有一個處理頁面+業務邏輯的應用程序。

我在Jackson序列化輸出時拋出org.hibernate.LazyInitializationException問題。

以下是我的JPA配置和相關的類。 我知道延遲初始化是由List成員引起的,但是我不希望在返回的JSON中填充它。 因此,@ JsonIgnore批注。

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

@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 + '\'' +
            '}';
}
}

我以為我需要配置某種會話管理器,但是不確定在JavaConfig中執行此操作的最佳方法,我已經通過Google嘗試了各種方法,但都不太高興。

任何幫助將非常感激。

更新

我現在設法通過以下方法解決此問題:1)在相關集合中添加@Fetch()批注,這意味着將填充集合2)我已停止將實體/模型作為JSON對象返回,而是使用單獨的DTO

從會話外部調用惰性字段時,會發生org.hibernate.LazyInitializationException
在您所處的情況下,您可以選擇ForumGroup實體,然后在會話之外嘗試調用entity.getForums() 這就是為什么發生LazyInitializationException的原因。

如果您需要該集合,請急切加載它們。 您可以通過以下方式實現:
entity.getForums().size(); 記住,在會話中調用它

您可以使用注釋默認情況下自動加載EAGERLY@ManyToOne(fetch = FetchType.EAGER)

您只需要獲取ForumGroup及其論壇列表即可。

每當您檢索感興趣的ForumGroup時,都可以使用LEFT JOIN FETCH來實現:

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

您可以分配默認的提取策略,但這是一個會影響后續查詢的決定,因此請確保您知道以下折衷方案:

使用聯接獲取模式:

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

或子選擇獲取模式:

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

並且始終初始化您的集合,永遠不要讓它們分配為null。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM