2010-04-20 77 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