Java 高效提取多个行李

Java 高效提取多个行李,java,hibernate,Java,Hibernate,我正在开发一个多语言应用程序。由于这个原因,许多对象的名称和描述字段中都有我称之为LocalizedStrings而不是普通字符串的集合。每个LocalizedString基本上是一对区域设置和一个本地化到该区域设置的字符串 让我们以一个实体为例,比如一个book-object public class Book{ @OneToMany private List<LocalizedString> names; @OneToMany private List<Loca

我正在开发一个多语言应用程序。由于这个原因,许多对象的名称和描述字段中都有我称之为LocalizedStrings而不是普通字符串的集合。每个LocalizedString基本上是一对区域设置和一个本地化到该区域设置的字符串

让我们以一个实体为例,比如一个book-object

public class Book{

 @OneToMany
 private List<LocalizedString> names;

 @OneToMany
 private List<LocalizedString> description;

 //and so on...
}
公共课堂教材{
@独身癖
私人名单名称;
@独身癖
私有列表描述;
//等等。。。
}
当用户要求提供书籍列表时,它会执行查询以获取所有书籍,获取用户选择运行应用程序的区域设置中每本书的名称和说明,并将其显示回用户

这是可行的,但这是一个主要的性能问题。目前hibernate只进行一次查询以获取所有书籍,然后它遍历每个对象,并向hibernate请求该特定对象的本地化字符串,从而导致“n+1选择问题”。获取50个实体的列表会在我的服务器日志中生成大约6000行sql命令

我试着让收集变得更迫切,但这让我想到了“不能同时取回多个袋子”的问题

然后我尝试将集合上的获取策略设置为subselect,希望它能对所有书籍执行一次查询,然后执行一次查询,为所有书籍获取所有本地化字符串。在这种情况下,Subselect没有起到我所希望的作用,它基本上与我的第一个案例完全相同

关于如何优化这一点,我已经没有什么想法了


简言之,当您提取一个集合,并且该集合中的每个元素本身都有一个或多个集合,必须同时提取时,有哪些提取策略可供选择。

当初始化一个单元化集合时,您可以在行李上设置一个
批量大小
,Hibernate将通过一个查询初始化其他一些集合

你说的更多

我尝试将集合的获取策略设置为subselect,希望它能对所有书籍执行一次查询

可以,但需要访问某些属性才能抛出子选择

@Entity
public class Book{

    private List<LocalizedString> nameList = new ArrayList<LocalizedString>();

    @OneToMany(cascade=javax.persistence.CascadeType.ALL)
    @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
    public List<LocalizedString> getNameList() {
        return this.nameList;
    }

    private List<LocalizedString> descriptionList = new ArrayList<LocalizedString>();

    @OneToMany(cascade=javax.persistence.CascadeType.ALL)
    @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
    private List<LocalizedString> getDescriptionList() {
        return this.descriptionList;
    }



}
Hibernate:返回100行(如预期)

Hibernate:返回100行(如预期)


三个select语句。没有“n+1”选择问题。请注意,我使用的是财产访问策略而不是字段。请记住这一点。

嗨,Jens,看一看:我希望它会有用。您不必访问某些属性,也可以启动subselect。更准确地说,您在这里这样做了,因为您没有将fetch类型设置为eager。如果将fetch type设置为eager,并将fetch mode设置为subselect,则它将自动触发subselect。
public class BookRepository implements Repository {

    public List<Book> getAll(BookFetchingStrategy fetchingStrategy) {
        switch(fetchingStrategy) {
            case BOOK_WITH_NAMES_AND_DESCRIPTIONS:
                List<Book> bookList = session.createQuery("from Book").list();

                // Notice empty statement in order to start each subselect
                for (Book book : bookList) {
                    for (Name address: book.getNameList());
                    for (Description description: book.getDescriptionList());
                }

            return bookList;
        }
    }

    public static enum BookFetchingStrategy {
        BOOK_WITH_NAMES_AND_DESCRIPTIONS;
    }

}
SessionFactory sessionFactory = configuration.buildSessionFactory();

Session session = sessionFactory.openSession();
session.beginTransaction();

// Ten books
for (int i = 0; i < 10; i++) {
    Book book = new Book();
    book.setName(RandomStringUtils.random(13, true, false));

    // For each book, Ten names and descriptions
    for (int j = 0; j < 10; j++) {
        Name name = new Name();
        name.setSomething(RandomStringUtils.random(13, true, false));

        Description description = new Description();
        description.setSomething(RandomStringUtils.random(13, true, false));

        book.getNameList().add(name);
        book.getDescriptionList().add(description);
    }

    session.save(book);
}

session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();

List<Book> bookList = session.createQuery("from Book").list();

for (Book book : bookList) {
    for (Name address: book.getNameList());
    for (Description description: book.getDescriptionList());
}

session.getTransaction().commit();
session.close();
select
    book0_.id as id0_,
    book0_.name as name0_ 
from
    BOOK book0_
select
    namelist0_.BOOK_ID as BOOK3_1_,
    namelist0_.id as id1_,
    namelist0_.id as id1_0_,
    namelist0_.something as something1_0_ 
from
    NAME namelist0_ 
where
    namelist0_.BOOK_ID in (
        select
            book0_.id 
        from
            BOOK book0_
    )
select
    descriptio0_.BOOK_ID as BOOK3_1_,
    descriptio0_.id as id1_,
    descriptio0_.id as id2_0_,
    descriptio0_.something as something2_0_ 
from
    DESCRIPTION descriptio0_ 
where
    descriptio0_.BOOK_ID in (
        select
            book0_.id 
        from
            BOOK book0_
    )