2015-10-20 62 views
4

我有一個簡單的@OneToMany關係的兩個對象看起來如下:春季啓動JPA - 一對多關係導致無限循環

父:

@Entity 
public class ParentAccount { 

    @Id 
    @GeneratedValue 
    private long id; 
    private String name; 

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "parentAccount") 
    private Set<LinkedAccount> linkedAccounts; 

} 

孩子:

@Entity 
public class LinkedAccount { 

    @Id 
    @GeneratedValue 
    private long id; 

    @ManyToOne(optional = false) 
    private ParentAccount parentAccount; 

    private String name; 

    // empty constructor for JPA 
    public LinkedAccount() { 
    } 

} 

我ma使用Spring CrudRepository來操作這些實體。但是,調用ParentAccount parent = parentAccountRepository.findOne(id);時,某種無限循環的開始發生,冬眠垃圾郵件這遍控制檯:

Hibernate: select linkedacco0_.parent_account_id as parent_a6_1_0_, linkedacco0_.id as id1_0_0_, linkedacco0_.id as id1_0_1_, linkedacco0_.aws_id as aws_id2_0_1_, linkedacco0_.key_id as key_id3_0_1_, linkedacco0_.name as name4_0_1_, linkedacco0_.parent_account_id as parent_a6_0_1_, linkedacco0_.secret_key as secret_k5_0_1_ from linked_account linkedacco0_ where linkedacco0_.parent_account_id=? 

我試着改變了獲取類型LAZY但後來我得到這個錯誤:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.berrycloud.scheduler.model.ParentAccount.linkedAccounts, could not initialize proxy - no Session 

(似乎它試圖在事務上下文之外執行延遲加載)。

這是我的CRUD庫:

@Repository 
public interface ParentAccountRepository extends CrudRepository<ParentAccount, Long> { 
} 

有人能告訴我如何解決這個問題?我更喜歡EAGER獲取的解決方案。感謝您的任何提示

編輯:這是我使用

CREATE TABLE parent_account (
    id BIGINT auto_increment, 
    name VARCHAR(80) null, 
    PRIMARY KEY (`id`) 
); 

CREATE TABLE linked_account (
    id BIGINT auto_increment, 
    parent_account_id BIGINT, 
    name VARCHAR(80) null, 
    FOREIGN KEY (`parent_account_id`) REFERENCES `parent_account` (`id`), 
    PRIMARY KEY (`id`) 
); 
+0

那麼,每個父帳戶有幾個鏈接的帳戶。而已。我沒有看到這可以解析成樹圖。深度應該是1. – Smajl

+0

在您的映射或模式中沒有錯誤...我不認爲您的無限循環問題來自...您是否在做這些對象中的其他任何事情?一些JSON/Jackson註釋可能? – Pras

回答

5

問題解決了。我正在引用ParentAccount的LinkedAccount中使用自定義的@toString方法。我不知道這可能會導致任何問題,因此我沒有在我的問題中包含toString。

顯然,這導致了無限循環的延遲加載,並刪除此引用解決了問題。

0

像這樣的東西不起作用的架構?

@Entity 
public class Account { 

    @Id 
    @GeneratedValue 
    private long id; 
    private String name; 

    @ManyToOne(cascade={CascadeType.ALL}) 
    @JoinColumn(name="manager_id") 
    private Account manager; 

    @OneToMany((fetch = FetchType.EAGER, mappedBy="manager") 
    private Set<Account> linkedAccounts = new HashSet<Account>(); 

} 
+0

我將不得不編輯我的sql模式(已存在)來添加manager_id列。此外,春天有這樣做的自動,所以我想用默認的JPA的JPA方式來解決這個問題 – Smajl

+0

什麼是非彈簧JPA呢?順便說一句,你的代碼適合我,你的數據庫中的數據有錯誤。檢查兩次。 – Mejmo

+0

我編輯了我的問題並添加了我正在使用的模式。也許有什麼問題呢? – Smajl

6

作爲第一答案提示:

Do not use Lombok's @Data annotation on @Entity classes.

原因是:@Data生成hashcode()equals()toString()方法,其使用所生成的吸氣劑。使用吸氣手段當然可以獲取新數據,即使屬性標記爲FetchType = LAZY

某處hibernate試圖用toString()記錄數據並崩潰。

+0

龍目確實是內存模型創建無限循環的原因,在我的情況下最終導致了StackOverflowError。儘管如此,我發現龍目島的getters和setters一代太有用了,完全放棄了它。 因此,我只通過將我自己的_toString()_方法添加到剛剛返回_super.toString()_的類來禁用Lombok生成_toString()_並解決了我的問題。 – Lev