JPA。 FetchType.Lazy 引起了奇怪的行为@ManyToOne

Posted

技术标签:

【中文标题】JPA。 FetchType.Lazy 引起了奇怪的行为@ManyToOne【英文标题】:JPA. FetchType.Lazy caused strange behaviour @ManyToOne 【发布时间】:2016-10-29 13:01:26 【问题描述】:

我正在尝试提高使用 JPA 的项目的性能。

我正在使用 JPA 2.1 和 Hibernate 5.0.1 实现。


我将 ManyToOne 关系的 FetchType 更改为 Lazy,所以事情搞砸了。

当我尝试查找子对象的所有记录时:最后一条记录带有所有空字段和 handler=JavassistLazyInitializer。这种奇怪的行为会影响使用此对象的字段(如 h:OneSelectMenu)。

如果我删除 FetchType.Lazy,事情就会恢复正常。

一些印刷品:

Debug child list 2

FetchType.Lazy

第二次打印代码(FetchType.Lazy):

public class Usuario implements Serializable 
  private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Id_Usuario")
private Integer idUsuario;

// Fields ...

@JoinColumn(name = "Id_Tipo_Logradouro", referencedColumnName = "Id_Tipo_Logradouro", nullable = true)
@ManyToOne(optional = true, fetch = FetchType.LAZY)
private TipoLogradouro tipoLogradouro;

@JoinColumn(name = "Id_Tipo_Usuario", referencedColumnName = "Id_Tipo_Usuario")
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private TipoUsuario tipoUsuario;

@JoinColumn(name = "Id_Supervisor", referencedColumnName = "Id_Usuario")
@ManyToOne(optional = true, fetch = FetchType.LAZY)
private Usuario supervisor;

// Contructor, Getters Setters etc ...

public class TipoUsuario implements Serializable 
private static final long serialVersionUID = 1L;

@Id
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 1)
@Column(name = "Id_Tipo_Usuario")
private String idTipoUsuario;

@Basic(optional = false)
@NotNull
@Size(min = 1, max = 20)
@Column(name = "Descricao")
private String descricao;

@Basic(optional = false)
@NotNull
@Size(min = 1, max = 1)
@Column(name = "Possui_Supervisor")
private String possuiSupervisor;

@Size(max = 1)
@Column(name = "Possui_Meta")
private String possuiMeta;

@Size(max = 1)
@Column(name = "Recebe_Alerta")
private String recebeAlerta;

@Transient
private List<Usuario> usuarioList = new ArrayList<>();

//Contructor, Getters Setters etc ...

【问题讨论】:

嗨,您可以将您的堆栈跟踪作为文本添加到问题中吗?图像可能会被阻止并且读取/复制很麻烦。 我想知道你为什么没有 org.hibernate.LazyInitializationException 被解雇,你能发布休眠和持久性配置 @Dubes,好的!我改了,但第一次打印的不是代码。 【参考方案1】:

为什么

使用延迟加载,您是在指示 EntityManager 除非有人要求,否则不要获取这些详细信息。因此,如果在您的交易中,您没有要求获取 property,您只会获得它的代理。但是,如果您向该代理询问与该属性相关的任何事情,例如大小,EntityManager按需为您获取该信息。

看起来您正在使用 JSF 作为您的视图,现在在这种情况下,在您的模型询问这些详细信息之前,实体管理器已经完成了它的工作,因此它不知道它必须再次为您从数据库中获取这些详细信息。请记住,代理是序列化的,因此在您看来,您的集合看起来像是 null/空。

如何解决这个问题

正确答案取决于您的使用情况。

如果您当前延迟加载的信息总是需要在前端显示,那么将其延迟加载没有任何好处。

否则,如果您需要它仅在有人单击下拉菜单或其他内容时显示,那么您可以使用 Fetch Joins 根据 JPA 查询填充这些值。

否则,如果您有 EJB,则可以考虑扩展您的 EntityManager

每个选项都有很多细节,但您可以查看来自 Adam Bien 的 blog post,了解有关上述所有选项的更多详细信息以及更多信息!

更新 1:查看此answer,了解如何在服务器端加载延迟加载的属性。

【讨论】:

当我简单地调用“SELECT t FROM TipoUsuario t”时,会发生奇怪的行为(如打印'Debug child list 2'所示)。一个孤立的电话。 :( 假设属性是tipoUsario in t,当你发出一个简单的SELECT时,JPA不会获取LazyLoaded属性。您必须明确要求 JPA 为您执行此操作。尝试将查询更改为以下内容,让我知道它的进展情况SELECT t FROM TipoUsuario t JOIN FETCH t.tipoUsuario 这里是加入获取的官方文档的链接,以防您感兴趣。 docs.oracle.com/html/E24396_01/… 感谢您的帮助,但 TipoUsuario 中没有复杂类型。我编辑了帖子并包含了 TipoUsuario 类型。

以上是关于JPA。 FetchType.Lazy 引起了奇怪的行为@ManyToOne的主要内容,如果未能解决你的问题,请参考以下文章

JPA fetchType.Lazy 不工作

FetchType.Lazy 在 Spring Boot 中无法在 JPA 中工作

使用 FetchType.LAZY 防止 JPA/Hibernate 中的延迟加载(尤其是在使用 @Transactional 时)?

JPA 懒加载实践 fetch = FetchType.LAZY

FetchType.LAZY 不适用于@OneToOne 关系

hibernate FetchType理解