hibernate一对多关联:subselect或eager

时间:2013-06-08 20:07:24

标签: hibernate grails lazy-loading eager

在grails应用程序中,我的关系默认是懒惰的:

class Author{
    String name
    static mapping = {
         books lazy:false
    }
}

我有一个标准API查询来获取作者。 当我运行查询

Author.createCriteria().list{
    eq("name", "John")
}

我为每个作者提供了N + 1个子选择。

我的第二种方法就是像这样急切地拿书:

Author.createCriteria().list{
    eq("name", "John")
    fetchMode("books", FetchMode.JOIN)
}

在这种情况下,不会出现N + 1选择问题,但是我有一个JOIN查询。

哪种方法在性能和优化方面更好?

1 个答案:

答案 0 :(得分:0)

我认为你在问题的第一行默认为eager而不是lazy

要记住的要点
当关联包含在条件查询中时,它们默认为急切获取。

在您的情况下,您不需要books lazy:false中的地图Author优化而言,我会保证采用以下方法:

class Author {
    String name
    static hasMany = [books: Book]
    static mapping = {
         //books lazy:false (DO NOT NEED)
    }
}

class Book {
    String bookName
    //set belongsTo if you need bi-directional one-many
    //books gets cascade deleted when author is deleted
    //static belongsTo = [author: Author]
}

//Bootstrap
def author1 = new Author(name: "Dan Brown")
def book1 = new Book(bookName: "Da Vinci Code")
def book2 = new Book(bookName: "Angels And Demons")
def book3 = new Book(bookName: "Inferno")

[book1, book2, book3].each {author1.addToBooks(it)}
author1.save(flush: true, failOnError: true)

//Criteria
Author.createCriteria().list{
    eq("name", "Dan Brown")
    books{
       //books are eagerly fetched by default using inner join. No need to specify FetchMode.
    }
}

就性能而言,如果每个作者写过20000篇博客(用博客替换书籍),我会采用上述方法。热切地为n作者提供20000个博客将会受到影响。在这种情况下,我会选择懒惰的获取(N + 1)路由,并尝试根据我的要求过滤掉博客。如下所示:

def author = Author.findByName("Dan Brown")
def books = author.books
//Assume you have a field publishedYear in Book
def booksReleasedIn2013 = author.books.findAll{it.publishedYear == 2013} 
def booksReleasedBefore2013 = author.books.findAll{it.publishedYear < 2013} 

assert "Inferno" in booksReleasedIn2013*.bookName
assert "Angels And Demons" in booksReleasedBefore2013*.bookName

如果你没有这样的(博客案例)案例,那么我会将上面引用的例子用于优化性能