一对一外键映射
One to One foreign key mapping
在 Book 和 author 之间的以下映射中,我使用 book table 中的外键列 author_id 完成了一对一映射,并且关系被标记为 optional false from book->author ,但是当我查询时
session.createQuery("from Book").list();
1) 当标记为可选为 false 时,它正在急切地获取作者信息,为什么不代理它,有人可以解释为什么它不能像在主键连接列中那样使用外键方法吗?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_, book0_.AUTHOR_ID as AUTHOR_I5_1_, book0_.description as descript2_1_, book0_.PUBLISHED as PUBLISHE3_1_, book0_.title as title4_1_ from BOOK book0_
Hibernate: select author0_.AUTHOR_ID as AUTHOR_I1_0_0_, author0_.email as email2_0_0_, author0_.name as name3_0_0_ from AUTHOR author0_ where author0_.AUTHOR_ID in (?, ?, ?)
Hibernate: select author0_.AUTHOR_ID as AUTHOR_I1_0_0_, author0_.email as email2_0_0_, author0_.name as name3_0_0_ from AUTHOR author0_ where author0_.AUTHOR_ID in (?, ?, ?)
@Entity
@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,optional=false)
@JoinColumn(name = "AUTHOR_ID")
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
@Entity
@BatchSize(size=3)
@Table(name = "AUTHOR")
public class Author {
private long id;
private String name;
private String email;
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;
}
}
2) 当我从 author->book 进行双向查询时,运行 查询
session.createQuery("from Author").list();
它首先按预期从 Author 获取记录,然后 运行 如下使用 2 个连接的单个查询。
为什么它必须进行连接而不是直接使用作者 ID 查询图书 table?
Hibernate: select author0_.AUTHOR_ID as AUTHOR_I1_0_, author0_.email as email2_0_, author0_.name as name3_0_ from AUTHOR author0_
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate 仅代理标记为 LAZY=true 的模型。以下线程可能会帮助您回答某些问题。 Hibernate lazy loading, optional = false
1) ToOne
关联在 JPA 中默认是急切的。使其变得懒惰:
@OneToOne(cascade = CascadeType.ALL, optional = false, , fetch = FetchType.LAZY)
用不用@PrimaryKeyJoinColumn
都无所谓
2) 没错,这是不必要的,Hibernate 可以做得更好;请看这个 。关键是 Hibernate 希望在急切地获取关联实体时避免额外的查询。
那么,这里发生了什么?
首先,您可能没有在 Author
方面声明关联是强制性的(这就是 left outer join
的来源)。
其次,Hibernate 通过提供的作者 ID 阅读书籍(对于第一个查询返回的每个作者)。如果您手动执行,您将得到相同的查询:
select b from Book b where b.author.id = :authorId
Hibernate使用第一个join table读这本书,第二个join读这本书的作者,第三个读作者的书。
这里不需要第三个连接 table,我希望 Hibernate 在未来的版本中对此进行改进。
第二个连接 table 如果您手动执行上述查询(在同一个查询中而不是在新查询中阅读图书的作者),那么第二个连接 table 是一个很好的优化,但在您的示例中是不必要的,因为所需的作者已经加载。我希望在未来的版本中也会对此进行改进。
PS Author
和 Book
之间的真实关联是一对多的。
在 Book 和 author 之间的以下映射中,我使用 book table 中的外键列 author_id 完成了一对一映射,并且关系被标记为 optional false from book->author ,但是当我查询时 session.createQuery("from Book").list();
1) 当标记为可选为 false 时,它正在急切地获取作者信息,为什么不代理它,有人可以解释为什么它不能像在主键连接列中那样使用外键方法吗?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_, book0_.AUTHOR_ID as AUTHOR_I5_1_, book0_.description as descript2_1_, book0_.PUBLISHED as PUBLISHE3_1_, book0_.title as title4_1_ from BOOK book0_
Hibernate: select author0_.AUTHOR_ID as AUTHOR_I1_0_0_, author0_.email as email2_0_0_, author0_.name as name3_0_0_ from AUTHOR author0_ where author0_.AUTHOR_ID in (?, ?, ?)
Hibernate: select author0_.AUTHOR_ID as AUTHOR_I1_0_0_, author0_.email as email2_0_0_, author0_.name as name3_0_0_ from AUTHOR author0_ where author0_.AUTHOR_ID in (?, ?, ?)
@Entity
@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,optional=false)
@JoinColumn(name = "AUTHOR_ID")
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
@Entity
@BatchSize(size=3)
@Table(name = "AUTHOR")
public class Author {
private long id;
private String name;
private String email;
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;
}
}
2) 当我从 author->book 进行双向查询时,运行 查询 session.createQuery("from Author").list();
它首先按预期从 Author 获取记录,然后 运行 如下使用 2 个连接的单个查询。 为什么它必须进行连接而不是直接使用作者 ID 查询图书 table?
Hibernate: select author0_.AUTHOR_ID as AUTHOR_I1_0_, author0_.email as email2_0_, author0_.name as name3_0_ from AUTHOR author0_
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_2_, book0_.AUTHOR_ID as AUTHOR_I5_1_2_, book0_.description as descript2_1_2_, book0_.PUBLISHED as PUBLISHE3_1_2_, book0_.title as title4_1_2_, author1_.AUTHOR_ID as AUTHOR_I1_0_0_, author1_.email as email2_0_0_, author1_.name as name3_0_0_, book2_.BOOK_ID as BOOK_ID1_1_1_, book2_.AUTHOR_ID as AUTHOR_I5_1_1_, book2_.description as descript2_1_1_, book2_.PUBLISHED as PUBLISHE3_1_1_, book2_.title as title4_1_1_ from BOOK book0_ inner join AUTHOR author1_ on book0_.AUTHOR_ID=author1_.AUTHOR_ID left outer join BOOK book2_ on author1_.AUTHOR_ID=book2_.AUTHOR_ID where book0_.AUTHOR_ID=?
Hibernate 仅代理标记为 LAZY=true 的模型。以下线程可能会帮助您回答某些问题。 Hibernate lazy loading, optional = false
1) ToOne
关联在 JPA 中默认是急切的。使其变得懒惰:
@OneToOne(cascade = CascadeType.ALL, optional = false, , fetch = FetchType.LAZY)
用不用@PrimaryKeyJoinColumn
都无所谓
2) 没错,这是不必要的,Hibernate 可以做得更好;请看这个
那么,这里发生了什么?
首先,您可能没有在 Author
方面声明关联是强制性的(这就是 left outer join
的来源)。
其次,Hibernate 通过提供的作者 ID 阅读书籍(对于第一个查询返回的每个作者)。如果您手动执行,您将得到相同的查询:
select b from Book b where b.author.id = :authorId
Hibernate使用第一个join table读这本书,第二个join读这本书的作者,第三个读作者的书。
这里不需要第三个连接 table,我希望 Hibernate 在未来的版本中对此进行改进。
第二个连接 table 如果您手动执行上述查询(在同一个查询中而不是在新查询中阅读图书的作者),那么第二个连接 table 是一个很好的优化,但在您的示例中是不必要的,因为所需的作者已经加载。我希望在未来的版本中也会对此进行改进。
PS Author
和 Book
之间的真实关联是一对多的。