【问题标题】:LazyInitializationException when get EAGER fetch object OneToOne获取 EAGER 获取对象 OneToOne 时出现 LazyInitializationException
【发布时间】:2021-11-12 03:49:03
【问题描述】:

我有两个实体

@Entity
@Table(name = "user")
@Data
@Builder
@EqualsAndHashCode(callSuper=false)
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "name")
    private String name;    
    
    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @PrimaryKeyJoinColumn
    private UserLastLogin userLastLogin;
}


@Entity
@Table(name = "lastLogin")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString(onlyExplicitlyIncluded = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserLastLogin implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "name")
    private String userName;

    @Column(name = "date")
    private LocalDateTime date;

    @OneToOne
    @MapsId
    @JoinColumn(name = "name")
    private User user;

}

我使用带有 spring data 和 jpa 的 spring boot,在最新版本中休眠。 在文档中,@OneToOne 是默认的 EAGER,但是当我急切获取对象时,当我在 get 方法中不使用 @Transactional 时,我会得到lazyInitializationException。我不明白为什么...

    public UserDto getUser(String userName) {
        var user= userRepository.getById(userName);     
        d.getSystemUserLastLogin(); // this throw lazy initialization exception
        return mapper.entityToDto(d);
    }

当我将这个方法标记为@Transactioal 时,这个工作。但是,不建议在 get 方法中使用事务。我需要在这种关系中使用 EAGER fetch。

当我查看查询休眠时,我有一个选择,但子对象不可用。

Hibernate: 
    select
        user0_.name as nazwa1_4_0_,        
        user2_.name as name1_23_2_,        
        user2_.data as data3_23_2_ 
    from
        user0_     
    left outer join
       last_login user2_ 
            on user0_.name=user2_.name 
    where
        user0_.name=?

【问题讨论】:

    标签: spring-boot hibernate spring-data-jpa spring-data one-to-one


    【解决方案1】:

    问题在于,尽管 fetch 很急切,但使用了 lazy。这是由于使用了存储库中的 getById 方法,该方法仅检索对象的引用并在检索惰性时捕捉所有字段。更改为 findById 可以解决问题,因为 findById 需要一个对象,而不是引用。

    【讨论】:

      【解决方案2】:

      我建议您使用辅助表,如下所示:

      @Entity
      @Table(name = "user")
      @Data
      @Builder
      @EqualsAndHashCode(callSuper=false)
      @ToString
      @AllArgsConstructor
      @NoArgsConstructor
      @SecondaryTable(name = "lastLogin", pkJoinColumns = @PrimaryKeyJoinColumn(name = "name"))
      public class User implements Serializable {
          private static final long serialVersionUID = 1L;
      
          @Id
          @Column(name = "name")
          private String name;    
          
          @Column(table = "lastLogin", name = "date")
          private LocalDateTime date;
      }
      

      有关详细信息,另请参阅https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-19
        • 2012-07-01
        • 1970-01-01
        • 2012-08-04
        相关资源
        最近更新 更多