2017-07-21 63 views
0

在Java/Hibernate的應用我有兩個類CatKitten在雙向關係如下描繪慢得多:雙向變得比單向

public class Cat { 
    ... 
    @OneToMany(mappedBy="cat", fetch = FetchType.LAZY) 
    @OnDelete(action = OnDeleteAction.CASCADE) 
    @LazyCollection(LazyCollectionOption.EXTRA) 
    @Getter 
    @Setter 
    private List<Kitten> kittens = new LinkedList(); 
    public void addKitten(Kitten k) { 
    kittens.add(k); 
    } 
    ... 
} 

public class Kitten { 
    ... 
    @ManyToOne(fetch=FetchType.LAZY) 
    @Getter 
    @Setter 
    private Cat cat; 
    ... 
} 

在一個巨大的環20000 Kitten是添加到先前創建的不同Cat個實體。在for循環的重要代碼如下所示:

.... 
Kitten k = new Kitten(); 
k.setAttribut("foo"); 
k.setCat(currentCat);  // (a) line 
currentCat.addKitten(k); // (b) line 
daoFactory.getKittenDao().save(k); 
... 

的代碼工作,但不知何故,性能非常慢。在以前的迭代中(單向),應用程序要快得多。由於最終版本應該在100000Kitten上工作,所以必須有一種改進方法。如果我以上述代碼爲基準測試時間,大約需要40秒。如果我通過刪除線(a)或(b)來模擬單向,則兩種情況下都需要10秒鐘(但如果訪問對象後會產生裂縫)。

所以我的問題是: 難道我錯過的東西,或者是雙向的關係,在Hibernate中非常緩慢的內部維護?由於模擬單向速度要快得多,所以我期望雙向的運行時間大約爲15秒。

更新:

保存實體的代碼是一個SAX解析器的DefaultHandler裏面執行。因此,在解析XML結構,首先Cat保存在startElement()功能後來就Kitten將被保存在另一個startElement()通話。 關於@Bartun的建議/問題:我看了一下批處理。問題是,通過使用DAO和startElement()函數,很難說什麼時候有50個實體被保存來刷新會話。一個計數器可以做到這一點。但是,它沒有通過建立雙向性來解釋性能影響。 事務管理春天@Transactional上使用啓動XML解析功能。

+1

你有個人資料來看看你在哪裏出血嗎? – efekctive

+0

只是猜測,嘗試persist()而不是save()。 – Steve11235

+0

@ Steve11235堅持使它更糟糕。那麼運行時間是50秒。 – Thanthla

回答

1

我已經減少次insterts這樣的量e處理時間達到我可以接受的價值。它並沒有真正解決我的問題,但大大縮短了時間。如果其他人有同樣的問題,這裏是當前的代碼和一個簡短的解釋。

public class Cat { 
    ... 
    @OneToMany(mappedBy="cat", fetch = FetchType.LAZY) 
    @OnDelete(action = OnDeleteAction.CASCADE) 
    @LazyCollection(LazyCollectionOption.EXTRA) 
    @Getter 
    @Setter 
    private Set<Kitten> kittens = new HashSet(); 
    public void addKitten(Kitten k) { 
    k.setCat(this); 
    if (Hibernate.isInitialized(kittens)) kittens.add(k); //line X 
    } 
    ... 
} 

public class Kitten { 
    ... 
    @ManyToOne(fetch=FetchType.LAZY) 
    @OnDelete(action = OnDeleteAction.CASCADE) 
    @Getter 
    @Setter 
    private Cat cat; 
    ... 
} 
  • 最重要的是line X。在原始代碼中,每次添加小貓時,整個小貓列表都從數據庫中加載。正如我發現here,如果列表尚未公開化,則不得添加小貓。我知道,這必須謹慎處理,因爲在列表首次初始化之前,每隻小貓都必須保存在數據庫中。否則一切都不同步。
  • 沒有在上面的代碼illustraited,我改變了小貓持久性的結構,以啓用批量插入(Thx Bartun的鏈接)。現在,所有小貓都在分析過程結束時使用批處理來保存,而不是單獨保存每隻小貓。
  • 另一個小改進是從List更改爲Set,以在代碼後面啓用多個fetch joins