首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何避免MultipleBagFetchException

如何避免MultipleBagFetchException
EN

Stack Overflow用户
提问于 2020-05-30 13:08:12
回答 1查看 168关注 0票数 2

祝大家今天愉快!

在我的Spring项目中,我试图消除一个在我看来相当普遍的错误-- org.hibernate.loader.MultipleBagFetchException。我想实现getOneClothesById(Long id)getAllClothes()方法。

@ Service-layer中,我希望从Clothes (sizecategorycolor)获取数据并在屏幕上显示它们,并/或在发送到其他地方之前修改它们。

我读了几本书,甚至去了谷歌的第4页,但我想我还没有找到最好的解决方案。

人们建议采取以下方法来解决这个问题:

  1. 使用Set<...>而不是List<...> 链接:
代码语言:javascript
复制
- [SO\_Answer(2011)](https://stackoverflow.com/a/5865605/8992586)
- [Hibernate Tips: How to avoid Hibernate’s MultipleBagFetchException (OLD\_POST)](https://thorben-janssen.com/hibernate-tips-how-to-avoid-hibernates-multiplebagfetchexception/)

我的意见是:我相信这不是一个好办法。下面是与解释的链接:

代码语言:javascript
复制
- [The best way to fix the Hibernate MultipleBagFetchException](https://vladmihalcea.com/hibernate-multiplebagfetchexception/) 

  1. 使用Fetch.Eager而不是Fetch.Lazy,或者添加@LazyCollection(LazyCollectionOption.FALSE) 链接:

  1. 使用@OrderColumn (在-@IndexColumn之前) 链接:
代码语言:javascript
复制
- [SO\_Answer(2019)](https://stackoverflow.com/a/56753769/8992586)
- [SO\_Answer(2015)](https://stackoverflow.com/a/26393134/8992586) 

我的评论是:(部分)问题,但根据文档 -这将排除选项orderBy

  1. 使用的方法:链接:
代码语言:javascript
复制
- [Vlad's SO\_answer(2014)](https://stackoverflow.com/a/24676806/8992586)
- [Vlad's SO\_answer(2018)](https://stackoverflow.com/a/51055523/8992586)
- [Vlad's post on his own  website](https://vladmihalcea.com/hibernate-multiplebagfetchexception/)

我的评论是:我认为这是处理org.hibernate.LazyInitializationException的最好解决方案是他的。但是,我想采用他的方法来实现Spring (2.2.6.RELEASE)的现实。

我想要的:

我想在Spring框架的框架内找到一种更好的解决问题的方法。在描述数据库之后的答案本质上是,这是解决问题的一种解决方案。不过,我有以下问题:

  1. 我不喜欢使用@Transactional来消除问题org.hibernate.LazyInitializationException: failed to lazily initialize ...
  2. 如何正确地将这种方法放入一个单独的类中,以便重用它?如果我用注释ClothesRepositoryFetch创建类@Repository,然后在@Service-layer中调用这个存储库,这将是正确的解决方案。
  3. 只有JPA才能更好地解决这个问题吗?

我的数据库看起来像:

ClothesService.java

代码语言:javascript
复制
    @Transactional
    public ResultDTO getOneClothesById(Long id){

        ResultDTO resultDTO = new ResultDTO();

        //Getting clothes with Category
        Clothes clothes = entityManager
                .createQuery(
                        "select distinct clothes " +
                                "from Clothes clothes " +
                                "left join fetch clothes.categories " +
                                "where clothes.id = :id", Clothes.class)
                .setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
                .setParameter("id", id)
                .getSingleResult();

        //Getting clothes with Color
        clothes = entityManager
                .createQuery(
                        "select distinct clothes " +
                                "from Clothes clothes " +
                                "left join fetch clothes.colors color " +
                                "where clothes = :clothes", Clothes.class)
                .setParameter("clothes", clothes)
                .setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
                .getSingleResult();

        //Getting clothes with Size
        clothes = entityManager
                .createQuery(
                        "select distinct clothes " +
                                "from Clothes clothes " +
                                "left join fetch clothes.sizes size " +
                                "where clothes = :clothes", Clothes.class)
                .setParameter("clothes", clothes)
                .setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
                .getSingleResult();

        System.out.println(clothes.getCategories().size());
        System.out.println(clothes.getColors().size());
        System.out.println(clothes.getSizes().size());

        if (clothes != null){
            resultDTO.setResult(ResultForDTO.SUCCESS);
            resultDTO.addClothesDTO(converterClothesToDTO(clothes));
        } else {
            resultDTO.setResult(ResultForDTO.ERROR);
            resultDTO.setMessage("Невозможно найти одежду по такому ID");
        }

        return resultDTO;
    }

代码

Clothes.java:

代码语言:javascript
复制
@Entity
@Table
@NoArgsConstructor
@Getter
@Setter
@ToString
public class Clothes {

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

    @Column
    private String name;

    @Column
    private Double price;



    /*
    Color: ManyToMany
     */
    @ManyToMany(fetch = FetchType.LAZY,
            cascade = {
                    CascadeType.PERSIST,
                    CascadeType.MERGE
            })
    @JoinTable(name = "clother_color",
            joinColumns = { @JoinColumn(name = "clother_id") },
            inverseJoinColumns = { @JoinColumn(name = "color_id") })
    private List<Color> colors = new ArrayList<>();

    public void addColor(Color color) {
        colors.add(color);
        color.getClothes().add(this);
    }

    public void removeColor(Color color) {
        colors.remove(color);
        color.getClothes().remove(this);
    }



    /*
    Size: ManyToMany
     */
    @ManyToMany(fetch = FetchType.LAZY,
            cascade = {
                    CascadeType.PERSIST,
                    CascadeType.MERGE
            })
    @JoinTable(name = "clother_size",
            joinColumns = { @JoinColumn(name = "clother_id") },
            inverseJoinColumns = { @JoinColumn(name = "size_id") })
    private List<Size> sizes = new ArrayList<>();

    public void addSize(Size size) {
        sizes.add(size);
        size.getClothes().add(this);
    }

    public void removeSize(Size size) {
        sizes.remove(size);
        size.getClothes().remove(this);
    }



    /*
    Category: ManyToMany
     */
    @ManyToMany(fetch = FetchType.LAZY,
            cascade = {
                    CascadeType.PERSIST,
                    CascadeType.MERGE
            })
    @JoinTable(name = "clother_category",
            joinColumns = { @JoinColumn(name = "clother_id") },
            inverseJoinColumns = { @JoinColumn(name = "category_id") })
    private List<Category> categories = new ArrayList<>();

    public void addCategory(Category category) {
        categories.add(category);
        category.getClothes().add(this);
    }

    public void removeCategory(Category category) {
        categories.remove(category);
        category.getClothes().remove(this);
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Clothes clothes = (Clothes) o;
        return Objects.equals(id, clothes.id);
    }
}

Category.java:

类别,大小,颜色有一个共同的结构,所以我只介绍其中一个

代码语言:javascript
复制
@Entity
@Table
@NoArgsConstructor
@Getter
@Setter
public class Category {

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

    @Column
    private String name;

    @ManyToMany(mappedBy="categories")
    private List<Clothes> clothes = new ArrayList<>();

    public void addClothes(Clothes clothes) {
        this.clothes.add(clothes);
        clothes.getCategories().add(this);
    }

    public void removeClothes(Clothes clothes) {
        this.clothes.remove(clothes);
        clothes.getCategories().remove(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Category category = (Category) o;
        return Objects.equals(id, category.id);
    }
}
EN

回答 1

Stack Overflow用户

发布于 2022-05-20 11:12:34

这似乎是Hibernate的一个基本问题:为了避免笛卡尔产品,他们禁止使用多个List。快速修复是使用Set,但这并不能解决效率问题。解决这一问题的方法是使用实体图,如https://thorben-janssen.com/jpa-21-entity-graph-part-1-named-entity/所描述的。这样,您就可以为每个查询指定急切加载的内容。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62102885

复制
相关文章

相似问题

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