AdSense

網頁

2018/7/5

JPA 雙向一對多/多對一 Bidirectional One To Many / Many To One CascadeType.MERGE更新時出現StackOverflowError

錯誤發生的情境如下,一個部門Department有多個員工Employee的一對多/多對一關聯。


Employee.java

@Entity
@Table(name="Department")
public class Department {
    
    @id
    @Column(name="DepartmentId")
    private int departmentId;

    @OneToMany(mappedBy="employeeId", cascade={CascadeType.PERSIST, CascadeType.MERGE}) // 串聯新增和更新
    private List<Employee> employeeList;
    
    // getter and setter ommitted
}

Department.java

@Entity
@Table(name="Employee")
public class Employee {

    @id
    @Column(name="EmployeeId")
    private int employeeId;

    @ManyToOne
    @JoinColumn(name="departmentId")
    private Department department;
    
    // getter and setter ommitted
}

以上設定在串聯新增Department及所屬的Employee時沒有問題,但串聯更新(update)時出現了未知的StackOverflowError

最後是透過在@ManyToOne設定fetch=FetchType.LAZY解決。

Employee.java

@Entity
@Table(name="Department")
public class Department {
    
    @id
    @Column(name="DepartmentId")
    private int departmentId;

    @OneToMany(mappedBy="employeeId", cascade={CascadeType.PERSIST, CascadeType.MERGE}) // 串聯新增和更新
    private List<Employee> employeeList;
    
    // getter and setter ommitted
}

Department.java

@Entity
@Table(name="Employee")
public class Employee {

    @id
    @Column(name="EmployeeId")
    private int employeeId;

    @ManyToOne(fetch=FetchType.LAZY) // @ManyToOne JPA預設的fetch=FetchType.EAGER,改為FetchType.LAZY
    @JoinColumn(name="departmentId")
    private Department department;
    
    // getter and setter ommitted
}

查了一下錯誤原因脫不了無限迴圈的問題,我猜是因為@ManyToOne預設為FetchType.EAGER,我的程式在執行時會先查詢Department物件,因此所屬的Employee與關聯的Department(即被查詢的Department本身)會同時一併取出,而在更新查出的Department及關聯的Employee時,Employee所屬的Department物件一併被影響,形成無限迴圈而導致StackOverflowError

而改為@ManyToOne(fetch=FetchType.LAZY),則查詢時Employee關聯的Department並未一起取出(只有在存取時才會查詢),所以之後更新查詢出的實體時不會導致無窮迴圈。

另外在網路上找解法時,發現StackOverflowError錯誤也會出現在當覆寫toString()方法中彼此呼叫了關聯物件的方法,在查詢時會引發。


沒有留言:

AdSense