Spring Boot JPA 延遲載入的坑

Spring Boot JPA 是一個很方便的工具,但再好的工具有時還是會遇到一些坑,當你的 Entity 有做 one to many 、 many to one 或 many to many 時,並使用 Lazy loading,在Web Application 時不會有問題,但當你用JUnit or 單獨的 Application 在執行時會遇見下列的錯誤;為什麼在 Web Application 不會有問題,因為在Spring Web 時會啟用:spring.jpa.open-in-view=true ,所以他當然不會有問題。
錯誤訊息:org.hibernate.LazyInitializationException: could not initialize proxy XXXXXXXX - no Session
那這問題要怎麼怎解呢? 假如你有下列的表格.

public class Category {
    private Integer id;
    @OneToMany(mappedBy = "parent")
    private List<Topic> topics;
}

public class Topic {
    private Integer id;
    @OneToMany(mappedBy = "parent")
    private List<Posts> posts;
    @ManyToOne
    @JoinColumn(name = "id")
    private Category parent;
}

public class Post {
    private Integer id;
    @ManyToOne
    @JoinColumn(name = "id")
    private Topic parent;
    /* Post fields */
}
public interface CategoryRepository extends JpaRepository<Category, Integer> {

}
public class CategoryRepositoryTest {
    @Test
    public void queryCategory() {
        Category categroy = categoryRepository.getOne(1);
        System.out.println(categroy);
        System.out.println(categroy.getTopic());
    }
}

在 application.properties 加入設定

在 application.properties 加入這個設定 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
這個是簡單的做法,當執行 System.out.println(categroy.getTopic()); 時,會再查詢取去得 Topic 資料,這樣是 1+1 = 2 次查詢,但當你 Entity 裡有多層的關聯時,他會執行 1+N 次查詢,也有可能會執行:1+N*M 次的查詢,想想這樣的做法上線可能會有的效能問題。

在 Repository 重新寫查詢方式

例如:

@Query("from Category c join fetch c.topics c where id = ?1 ")
public Category getOne(Integer id);

透過上述的方式,在第一次取得資料時就全部取回來了。

那個用法是最好,並沒有絕對,就取決您的應用及取捨。

Related Posts

發佈留言