在我们正在开发的这个应用程序中,我们注意到一个视图特别慢.我分析了视图并注意到hibernate执行了一个查询,即使数据库中只有两个对象要获取,也需要10秒.所有OneToMany和ManyToMany关系都是懒惰的,所以这不是问题.在检查正在执行的SQL时,我注意到查询中有超过80个连接.
进一步检查这个问题,我注意到问题是由实体类的深层次结构OneToOne和ManyToOne关系引起的.所以,我想,我只是让他们变得懒惰,这应该解决问题.但是,无论是标注@OneToOne(fetch=FetchType.LAZY)或@ManyToOne(fetch=FetchType.LAZY)似乎不工作.我得到一个异常,或者它们实际上并没有被代理对象替换,因此是懒惰的.
任何想法我将如何让这个工作?请注意,我不使用persistence.xml定义关系或配置细节,一切都在java代码中完成.
JPA的获取策略到底控制了什么?我无法发现渴望和懒惰之间的任何区别.在这两种情况下,JPA/Hibernate都不会自动加入多对一关系.
示例:Person有一个地址.地址可以属于很多人.JPA带注释的实体类看起来像:
@Entity
public class Person {
@Id
public Integer id;
public String name;
@ManyToOne(fetch=FetchType.LAZY or EAGER)
public Address address;
}
@Entity
public class Address {
@Id
public Integer id;
public String name;
}
Run Code Online (Sandbox Code Playgroud)
如果我使用JPA查询:
select p from Person p where ...
Run Code Online (Sandbox Code Playgroud)
JPA/Hibernate生成一个SQL查询以从Person表中进行选择,然后为每个人选择一个不同的地址查询:
select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3
Run Code Online (Sandbox Code Playgroud)
这对于大型结果集非常糟糕.如果有1000个人,则会生成1001个查询(1个来自Person,1000个来自地址).我知道这是因为我正在查看MySQL的查询日志.我的理解是,将地址的提取类型设置为eager会导致JPA/Hibernate自动使用连接进行查询.但是,无论获取类型如何,它仍会为关系生成不同的查询.
只有当我明确告诉它加入时它才真正加入:
select p, a from Person p left join p.address …Run Code Online (Sandbox Code Playgroud) 考虑以下型号:
@Entity
public class User {
@Id
@Column(name = "USER_ID")
private Long userId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@OneToOne
@PrimaryKeyJoinColumn
private UserExt userExt;
... //getters and setters
}
@Entity
public class UserExt {
@Id
@Column(name="USER_ID")
private Long id;
private String cdpId;
private Date lastChanged;
... //getters and setters
}
Run Code Online (Sandbox Code Playgroud)
执行时:
Query query = session.createQuery("from User");
List<User> list = query.list();
Run Code Online (Sandbox Code Playgroud)
Hibernate执行
Hibernate: select user0_.USER_ID as USER1_0_, user0_.FIRST_NAME as FIRST2_0_, user0_.LAST_NAME as LAST3_0_, user0_.EXT_USERNAME as …Run Code Online (Sandbox Code Playgroud) 拥有以下简化实体:
@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
}
@Entity
@Table(name = "t_invoice")
public class Invoice extends AbstractEntity {
@OneToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "order_id")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Order order;
}
@Entity
@Table(name = "t_order")
public class Order extends AbstractEntity {
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@SortNatural
private SortedSet<OrderLine> orderLines = new TreeSet<>();
@OneToOne(optional = true, mappedBy = …Run Code Online (Sandbox Code Playgroud)