延迟加载(一对一使用 FK)问题
Lazy loading (one to one using FK) issue
当执行session.createQuery("from Author").list()时;
即使关系标记为 optional=false,fetch type = lazy from Author->book 也会根据下面生成的 sql 急切地加载关联的书籍实例信息。
我将这种关系视为一对一只是为了理解目的,目前不是一对多。是否可以从作者书中让它变得懒惰,如果不确定我错过了什么?
Hibernate:select author0_.AUTHOR_ID 作为 AUTHOR_I1_0_,author0_.email 作为 email2_0_,author0_.name 作为 name3_0_ 来自作者 author0_
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
@Entity
@BatchSize(size=3)
@Table(name = "AUTHOR")
public class Author {
private long id;
private String name;
private String email;
private Book book;
public Author() {
}
public Author(String name, String email) {
this.name = name;
this.email = email;
}
@Id
@Column(name = "AUTHOR_ID")
@GeneratedValue
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=false,mappedBy="author")
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
@Entity
@BatchSize(size=3)
@Table(name = "BOOK")
public class Book {
private long id;
private String title;
private String description;
private Date publishedDate;
private Author author;
public Book() {
}
@Id
@Column(name = "BOOK_ID")
@GeneratedValue
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Temporal(TemporalType.DATE)
@Column(name = "PUBLISHED")
public Date getPublishedDate() {
return publishedDate;
}
public void setPublishedDate(Date publishedDate) {
this.publishedDate = publishedDate;
}
@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=false)
@JoinColumn(name ="AUTHOR_ID",unique=true)
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
你错过了从 Author
到 Book
的 link 不是双向关联的定义所有者,我的意思是它被定义为 mappedBy 并且 FK 位于Book
table。
因此,当检索到作者时,它需要查询 Book table 以检查 FK 并找出是否有书以及每个作者关联的书。这就是为什么您在书 table 上看到的 select 语句与您拥有的作者一样多(这被称为 N+1 查询问题)。
避免这种情况的一种方法是切换关联的所有者方(在作者 table 中定义书籍的外键),但您会看到类似的查询书籍的行为。
如果您关心附属查询,一种选择是在查询中应用提取策略,强制检索与作者关联的书籍。查询将类似于,
session.createQuery("from Author a left join fetch a.book").list();
我告诉了你原因和基本的 solution/workaround 但还有更复杂的选项,你肯定可以在 Whosebug 中找到它们。
当执行session.createQuery("from Author").list()时; 即使关系标记为 optional=false,fetch type = lazy from Author->book 也会根据下面生成的 sql 急切地加载关联的书籍实例信息。 我将这种关系视为一对一只是为了理解目的,目前不是一对多。是否可以从作者书中让它变得懒惰,如果不确定我错过了什么?
Hibernate:select author0_.AUTHOR_ID 作为 AUTHOR_I1_0_,author0_.email 作为 email2_0_,author0_.name 作为 name3_0_ 来自作者 author0_
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
休眠:select book0_.BOOK_ID 作为 BOOK_ID1_1_0_,book0_.AUTHOR_ID 作为 AUTHOR_I5_1_0_,book0_.description 作为 descript2_1_0_,book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?
@Entity
@BatchSize(size=3)
@Table(name = "AUTHOR")
public class Author {
private long id;
private String name;
private String email;
private Book book;
public Author() {
}
public Author(String name, String email) {
this.name = name;
this.email = email;
}
@Id
@Column(name = "AUTHOR_ID")
@GeneratedValue
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=false,mappedBy="author")
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
@Entity
@BatchSize(size=3)
@Table(name = "BOOK")
public class Book {
private long id;
private String title;
private String description;
private Date publishedDate;
private Author author;
public Book() {
}
@Id
@Column(name = "BOOK_ID")
@GeneratedValue
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Temporal(TemporalType.DATE)
@Column(name = "PUBLISHED")
public Date getPublishedDate() {
return publishedDate;
}
public void setPublishedDate(Date publishedDate) {
this.publishedDate = publishedDate;
}
@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=false)
@JoinColumn(name ="AUTHOR_ID",unique=true)
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
你错过了从 Author
到 Book
的 link 不是双向关联的定义所有者,我的意思是它被定义为 mappedBy 并且 FK 位于Book
table。
因此,当检索到作者时,它需要查询 Book table 以检查 FK 并找出是否有书以及每个作者关联的书。这就是为什么您在书 table 上看到的 select 语句与您拥有的作者一样多(这被称为 N+1 查询问题)。
避免这种情况的一种方法是切换关联的所有者方(在作者 table 中定义书籍的外键),但您会看到类似的查询书籍的行为。
如果您关心附属查询,一种选择是在查询中应用提取策略,强制检索与作者关联的书籍。查询将类似于,
session.createQuery("from Author a left join fetch a.book").list();
我告诉了你原因和基本的 solution/workaround 但还有更复杂的选项,你肯定可以在 Whosebug 中找到它们。