2010-04-20 74 views
3

我正在开发一个多语言应用程序。出于这个原因,许多对象在其名称和描述字段中都有一些我调用LocalizedStrings而不是普通字符串的集合。每个LocalizedString基本上都是一对语言环境和一个本地化到该语言环境的字符串。高效地提取多个袋子

让我们以一个实体为例,让我们说一本书 - 对象。

public class Book{ 

@OneToMany 
private List<LocalizedString> names; 

@OneToMany 
private List<LocalizedString> description; 

//and so on... 
} 

当用户请求一个书单,它查询来获取所有的书,获取用户选择运行的应用程序的名称,每本书在语言环境的描述,并显示它回到用户。

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

我试着让藏品渴望,但这导致我“不能同时取多个袋子” - 发行。

然后我试着设置集合上的获取策略来进行子选择,希望它会为所有书籍执行一个查询,然后执行一个查询以获取所有书籍的所有LocalizedStrings。子选择在这种情况下不起作用,我希望如何,基本上和我的第一种情况完全一样。

我开始意识到如何优化这一点。

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

+0

您好Jens,看看:http://www.jroller.com/eyallupu/entry/hibernate_exception_simultaneously_fetch_multiple http://www.jroller.com/eyallupu/entry/solving_simultaneously_fetch_multiple_bags和https://forum.hibernate。 org/viewtopic.php?t = 974127我希望它可以有用 – 2010-07-04 05:02:16

回答

3

你说一个单一的查询

我试图设置集合上的获取策略进行再选择,希望它会对所有图书执行一个查询

可以,但你需要访问一些财产扔子选择

@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; 
    } 



} 

执行如下操作

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_ 

休眠:返回100行(如预期)

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_ 
    ) 

休眠:返回100行(如预期)

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_ 
    ) 

Thre e选择语句。没有“n + 1”选择问题。请注意我正在使用属性访问策略而不是字段。记住这一点。

+0

您不必访问某些属性获取子查询触发。更准确地说,你在这里完成了这种设置,因为你没有设置抓取类型。如果您将获取类型设置为渴望并将获取模式设置为子选择,则它将自动激发您的子选择。 – 2010-08-13 18:18:47

1

你可以设置你的包包batch-size,当一个未初始化集合初始化,Hibernate会初始化一些其他集合与

更多的Hibernate doc