代码之家  ›  专栏  ›  技术社区  ›  Chiu

NullPointerException发生在FetchType中。懒散的冬眠和春靴

  •  4
  • Chiu  · 技术社区  · 6 年前

    使现代化

    我想指出@sainr的回答 Converting Hibernate proxy to real entity object 确实解决了问题。但幕后的问题是我 SiteEntity 拥有 final 它的修饰符 setControllerEntity getControllerEntity ,我在问题中没有提出。我道歉。

    移除 最终的 修改器。然后Hibernate可以很好地初始化代理对象。

    解释可以在另一个 answer 堆栈溢出时。


    我有以下三个实体

    @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 这是由于 null 控制性 siteEntity .

    而且,即使我尝试使用 siteRepositoy 再次获取siteEntity。这个 控制性 当然还是 无效的 .

    在我移除 fetch = FetchType.LAZY 从DeviceEntity和SiteEntity来看,NPE不再发生。

    但这似乎很奇怪,没有意义。我可以使用 FetchType.LAZY 期望hibernate获取正确的值时?

    谢谢

    2 回复  |  直到 6 年前
        1
  •  2
  •   Vladimir Salin    6 年前

    为您提供对用声明的字段的访问权限 FetchType.LAZY ,Hibernate用CGLIB构造一个代理。因此,当您为此类字段调用getter时(在您的情况下, getSiteEntity() getControllerEntity() ),您没有直接访问字段值,而是将调用传递给Hibernate的代理对象。反过来,Hibernate尝试从数据存储中加载实际值,为此,需要一个活动的Hibernate会话来访问数据库。最有可能的是,在您的情况下,Hibernate会话已经关闭,这样的延迟加载失败,给您一个有效的 null 字段的值。

    基本上有两种解决方法:

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

    想想看,在你的情况下,你是否真的需要一个懒散的负载。如果您没有在子字段中存储大量的重物以按需加载它们,可能会切换到 FetchType。热切的 将是最简单的方法。

    希望这有帮助。

        2
  •  2
  •   Anton Tupy    6 年前

    Hibernate有时不能很好地处理基元类型。尝试替换

    private long id
    

    private Long id
    

    对于Hibernate中的主键,最好使用包装类而不是基元类型。