【问题标题】:Why are my collections getting eagerly initialized despite the FetchType.LAZY?尽管有 FetchType.LAZY,为什么我的集合却被急切地初始化?
【发布时间】:2021-11-17 04:43:07
【问题描述】:

我开始从事我的项目并希望将 Hibernate 与 JpaRepositories 一起使用。由于我不熟悉这些可能是一个愚蠢的问题,但是,我不知道为什么我的关联集合会急切地初始化。

我的课程(简体):

@Entity(name = "board")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Board_Type")
public abstract class Board {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "board_id", updatable = false)
    private Long boardId;

    @Column(name = "board_name")
    private String boardName;

    @ManyToMany
    @JoinTable(name = "board_status",
                joinColumns = {@JoinColumn(name = "fk_board")},
                inverseJoinColumns = {@JoinColumn(name = "fk_status")})
    private Set<Status> availableStatuses = new HashSet<>();

    @OneToMany(mappedBy = "board", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JsonManagedReference
    private List<Task> taskList = new ArrayList<>();

子类:

@Entity
@DiscriminatorValue(value = "Simple_Board")
public class SimpleBoard extends Board{
    @ManyToOne(fetch = FetchType.LAZY)
    @JsonBackReference
    private User owner;

任务类:

@Entity(name = "task")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Task {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "task_id)
    private Long taskId;

    private String taskName;

    @OneToMany(mappedBy = "task", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JsonManagedReference
    private List<Comment> commentList = new ArrayList<>();;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonBackReference
    private User creator;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "board_id")
    @JsonBackReference
    private Board board;

评论类:

@Entity(name = "comment")
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "comment_id", updatable = false)
    private Long commentId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonBackReference
    private User creator;

    private String content;

    private LocalDateTime creationDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonBackReference
    private Task task;

用户类别:

@Entity(name = "user")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "User_Type")
public abstract class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id", updatable = false)
    private Long userId;

    private String login;

    private String password;

    private String email;

    private LocalDateTime registerDate;

用户子类:

@Entity
@DiscriminatorValue(value = "App_User")
public class ApplicationUser extends User{

    private String firstName;

    private String lastName;

    @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @JsonManagedReference
    private List<SimpleBoard> personalBoards = new ArrayList<>();

    @OneToMany(mappedBy="creator", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @JsonManagedReference
    private List<Task> userTasks = new ArrayList<>();

调用端点以获取具有给定 ID 的 Board:

@RestController
@RequestMapping("/board")
public class SimpleBoardController {
    private ApplicationUserService applicationUserService;
    private SimpleBoardService simpleBoardService;

    @Autowired
    public SimpleBoardController(SimpleBoardService simpleBoardService, ApplicationUserService applicationUserService) {
        this.simpleBoardService = simpleBoardService;
        this.applicationUserService = applicationUserService;
    }

    @GetMapping(value = "/{boardId}")
    public SimpleBoard getBoard(@PathVariable Long id){
        return simpleBoardService.getBoardById(id);
    }

服务方式:

    @Override
    public SimpleBoard getBoardById(Long id) {
        return simpleBoardDAO.getByBoardId(id);
    }

JpaRepository:

public interface SimpleBoardDAO extends JpaRepository<SimpleBoard, Long> {
    SimpleBoard save(SimpleBoard simpleBoard);

    SimpleBoard getByBoardId(Long id);

我使用 H2-db,为了创建一些测试数据,我使用 data.sql。然后我使用邮递员调用端点,响应是这样的:

{
    "boardId": 1,
    "boardName": "Test Board",
    "availableStatuses": [
        {
            "statusId": 3,
            "name": "Done",
            "sequence": 2
        },
        {
            "statusId": 2,
            "name": "In Progress",
            "sequence": 2
        },
        {
            "statusId": 1,
            "name": "To Do",
            "sequence": 1
        }
    ],
    "taskList": [
        {
            "taskId": 1,
            "taskName": "Create an To Do Application",
            "commentList": [
                {
                    "commentId": 1,
                    "content": "Nice job",
                    "creationDate": "2021-09-23T20:36:39.026"
                }
            ],
            "creationDate": "2021-09-23T20:36:39.024",
            "status": {
                "statusId": 1,
                "name": "To Do",
                "sequence": 1
            }
        }
    ]
}

我希望这个端点要么返回没有关联任务和评论的 Board,要么抛出异常,因为我没有使用任何图表或 JPQL Join Fetch 方法来初始化这些集合。 如您所见,董事会是与他们两人一起取来的。我知道这可能会在调试器模式下或通过调用与集合相关的一些方法发生,但我不会这样做。

这个项目的目的是学习JPA和Hibernate。我知道数据模型可能是一团糟,我需要再次考虑一下。希望有人可以向我解释。 提前致谢!

附:我知道延迟获取是默认设置,将 FetchType 放在关联的两侧是多余的。我只是绝望:D

【问题讨论】:

  • 您是如何确定获取正在急切进行的?我宁愿怀疑您实际上在这里遇到了 N+1 问题。您似乎将 数据库层 与 Web API 层 混淆了。
  • 您能详细说明一下吗?我认为获取正在急切地进行,因为调用 getByBoardId() 方法也会查询关联的任务和 cmets 集合,这不正是所谓的急切获取吗?
  • 这就是急切获取的意思,但您没有理由声称正在发生这种情况。具体来说,当您从控制器返回 SimpleBoard 时,集合 getter 在转换为 JSON 时被调用,从而触发低效的延迟获取。
  • 谢谢,这很有意义。我没有意识到在序列化对象时实际发生了这种情况。我现在将尝试弄清楚为什么这些效率低下以及如何改进它!我有很多要学习的。非常感谢您的帮助。干杯!

标签: java hibernate jpa orm


【解决方案1】:

根据文档@OneToMany

FetchType 获取 (可选)关联是应该延迟加载还是必须急切获取。 EAGER 策略是对持久性提供程序运行时的要求,即必须急切地获取关联的实体。 LAZY 策略是对持久性提供程序运行时的提示。

这可能与JPA fetchType.Lazy is not working 重复

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    • 2013-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    • 1970-01-01
    相关资源
    最近更新 更多