首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加载Hibernate实体时如何优化Carstesian产品

加载Hibernate实体时如何优化Carstesian产品
EN

Stack Overflow用户
提问于 2017-04-18 13:38:40
回答 1查看 195关注 0票数 2

为了演示我的问题,我创建了一个简单的Spring应用程序。它有一个实体,它有ID、两个String属性和两个Sets<String>集。

代码语言:javascript
复制
package com.mk.cat.domain;

import javax.persistence.*;
import java.util.Set;

@Entity
@Table(name = "cat")
public class Cat {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

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

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

    @ElementCollection(fetch = FetchType.EAGER)
    @Column(name = "color")
    @CollectionTable(
            name = "cat_color",
            joinColumns = @JoinColumn(name = "cat_id"))
    private Set<String> colors;

    @ElementCollection(fetch = FetchType.EAGER)
    @Column(name = "nickname")
    @CollectionTable(
            name = "cat_nickname",
            joinColumns = @JoinColumn(name = "cat_id"))
    private Set<String> nicknames;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Set<String> getColors() {
        return colors;
    }

    public void setColors(Set<String> colors) {
        this.colors = colors;
    }

    public Set<String> getNicknames() {
        return nicknames;
    }

    public void setNicknames(Set<String> nicknames) {
        this.nicknames = nicknames;
    }
}

还有一个简单的代码,它从DB持久化并加载Cat实体。

代码语言:javascript
复制
package com.mk.cat;

import com.google.common.collect.Sets;
import com.mk.cat.domain.Cat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CatApplication implements CommandLineRunner {

    private final CatRepository catRepository;

    private static final Logger LOGGER = LoggerFactory.getLogger(CatApplication.class);

    @Autowired
    public CatApplication(CatRepository catRepository) {
        this.catRepository = catRepository;
    }

    public static void main(String[] args) {
        SpringApplication.run(CatApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Cat cat = new Cat();
        cat.setName("Ben");
        cat.setSex("Male");
        cat.setNicknames(Sets.newHashSet("Fluffy", "Mr. Tomcat", "Catburger"));
        cat.setColors(Sets.newHashSet("Black", "White"));

        final Cat saved = catRepository.save(cat);
        LOGGER.info("Cat saved={}", cat);

        catRepository.findOne(saved.getId());
    }
}

我跟踪Hibernate,发现Cat是通过这个SQL从DB加载的。

代码语言:javascript
复制
select cat0_.id as id1_0_0_, 
    cat0_.name as name2_0_0_,
    cat0_.sex as sex3_0_0_,
    colors1_.cat_id as cat_id1_1_1_, 
    colors1_.color as color2_1_1_, 
    nicknames2_.cat_id as cat_id1_2_2_, 
    nicknames2_.nickname as nickname2_2_2_
  from cat cat0_ 
  left outer join cat_color colors1_ on cat0_.id=colors1_.cat_id 
  left outer join cat_nickname nicknames2_ on cat0_.id=nicknames2_.cat_id 
where cat0_.id=1

然后Hibernate从cat表的行和两个表中获得这个笛卡尔积,它们表示Cat#colorsCat#nicknames集。

代码语言:javascript
复制
id1_0_0_    name2_0_0_  sex3_0_0_   cat_id1_1_1_    color2_1_1_ cat_id1_2_2_    nickname2_2_2_
1   Ben Male    1   Black   1   Fluffy
1   Ben Male    1   Black   1   Catburger
1   Ben Male    1   Black   1   Mr. Tomcat
1   Ben Male    1   White   1   Fluffy
1   Ben Male    1   White   1   Catburger
1   Ben Male    1   White   1   Mr. Tomcat

然后Hibernate遍历每一行,解析ResultSet的每一项并创建实体。以某种方式优化这种方法是可能的吗?由于严重的性能问题,我想通过一个子选择来选择Cat#colorsCat#nicknames集。在实际情况中,我获取了1500个实体,这些实体具有复杂的结构,而且并不少见,一个获取的实体在相应的ResultSet中生成25.000行,导致解析时间非常长。

在我的情况下,延迟加载不是我想要使用的选项,因为它给代码带来了混乱。据我所知,延迟加载的集合必须通过第一个调用来初始化,在我的实际应用程序中,这是一个相当大的可用性代价。

我希望有3个单独的选择,一个来自cat表,一个来自cat_color表,一个来自cat_nickname表。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-20 10:30:20

我找到了Hibernate的解决方案,@Fetch(FetchMode.SELECT)完成了这项工作,因为它让Hibernate通过单独的select而不是join选择昵称。

代码语言:javascript
复制
@Fetch(FetchMode.SELECT)
@ElementCollection(fetch = FetchType.EAGER)
@Column(name = "nickname")
@CollectionTable(
        name = "cat_nickname",
        joinColumns = @JoinColumn(name = "cat_id"))
private Set<String> nicknames;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43473855

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档