java - NullPointerException 发生在 FetchType.LAZY withi hibernate 和 spring boot

标签 java hibernate spring-boot lazy-loading

更新

我想指出@sainr 的回答 Converting Hibernate proxy to real entity object确实解决了问题。但幕后的问题是我的 SiteEntity 有一个 final 修饰符是 setControllerEntitygetControllerEntity,我没有'提出我的问题。我道歉。

删除 final 修饰符。然后 Hibernate 可以很好地初始化代理对象。

解释可以在另一个answer中找到在 Stack Overflow 上。


我有如下三个实体

@Entity
@Table(name = "controller")
public class ControllerEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(nullable = false, updatable = false)
    private long id;
}

@Entity
@Table(name = "site")
public class SiteEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(nullable = false)
    private long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "controller_id", nullable = false)
    private ControllerEntity controllerEntity;
}

@Entity
@Table(name = "device")
public class DeviceEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(nullable = false)
    private long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "site_id", nullable = true)
    private SiteEntity siteEntity;
}

找到设备实体后,我尝试直接从中获取 controllerEntity

final DeviceEntity deviceEntity1 = deviceRepository.findOne(1L);
System.out.println(deviceEntity1.getSiteEntity().getControllerEntity().getId());

但它会导致 java.lang.NullPointerException,这是由 siteEntity 中的 null controllerEntity 引起的.

此外,即使我尝试使用 siteRepositoy 再次获取 siteEntity。它的 controllerEntity 仍然是 null

在我从 DeviceEntity 和 SiteEntity 中删除 fetch = FetchType.LAZY 后,NPE 不再发生。

但这看起来很奇怪而且没有意义。我可以使用 FetchType.LAZY 并期待 hibernate 获取正确的值吗?

谢谢。

最佳答案

为了让您能够访问使用 FetchType.LAZY 声明的字段,Hibernate 使用 CGLIB 构造了一个代理。因此,当您为此类字段调用 getter(在您的情况下为 getSiteEntity()getControllerEntity())时,您不会直接访问字段值 - - 相反,调用被传递给 Hibernate 的代理对象。反过来,Hibernate 会尝试从数据存储中加载实际值,为此,它需要一个 Activity 的 Hibernate session 来访问数据库。在您的情况下,Hibernate session 很可能已经关闭并且此类延迟加载失败,从而为您提供了该字段的有效 null 值。

基本上有两种方法可以解决这个问题:

  1. 使用 FetchType.EAGER 加载所有字段值以及持有对象 DeviceEntity
  2. 将代理对象转换为真实对象(检查Converting Hibernate proxy to real entity object)并以常规方式访问它

考虑一下,您的情况是否真的需要延迟加载。如果您没有在子字段中存储大量重对象以按需加载它们,那么切换到 FetchType.EAGER 可能是最简单的方法。

希望对您有所帮助。

关于java - NullPointerException 发生在 FetchType.LAZY withi hibernate 和 spring boot,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47987472/

相关文章:

java - j2me数据库查询包括条件

java - 实现迭代器时索引不递增

hibernate - 臭名昭著的: Invalid index n for this SqlParameterCollection with Count=

java - 如何在 spring-boot 中使用 2 个或更多 jdbcTemplate?

java - 如何使用 ImageWriter 和 ImageIO 在 Java 中编码动画 GIF?

java - 使用正则表达式解析log4j日志文件

java - 我可以在 Spring Boot + Hibernate 中通过文件加载用户名和密码吗?

Java 和 Hibernate - 如何与 SuperMappedClass 而不是实体建立 OneToOne 关系

java - Spring Boot 本地化问题 - Accept-Language header

java - spring中如何将整个表添加到缓存中