2013-08-29 60 views
1

我們最近遇到了JPA和查詢@ManyToOne/@OneToMany關係的問題,導致產生一個計算器。但是這隻發生在應用服務器由於已經創建實體而重新啓動的時候JPA + GSON:僅在服務器重新啓動後纔會在Stackoverflow中查詢

問題: 當我通常在部署了war文件的情況下啓動我的應用服務器時,我可以用我的數據庫填充一些內容並查詢它是否有什麼關係。 然而,當我重新啓動服務器,但不清除數據庫,我嘗試執行相同的查詢,我得到怪異的行爲:

我得到一個異常#1:

java.lang.StackOverflowError的

at java.lang.StringBuffer.append(StringBuffer.java:224) 

at java.io.StringWriter.write(StringWriter.java:84) 

at java.io.StringWriter.append(StringWriter.java:126) 

at java.io.StringWriter.append(StringWriter.java:24) 

at com.google.gson.stream.JsonWriter.beforeValue(JsonWriter.java:610) 

at com.google.gson.stream.JsonWriter.open(JsonWriter.java:317) 

at com.google.gson.stream.JsonWriter.beginObject(JsonWriter.java:300) 

at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:190) 

at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:879) 

at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) 

at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89) 

at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195) 

[...]

爲了完整:我的實體有如下關係:

任務實體:

@OneToMany(mappedBy = "mission", cascade=CascadeType.ALL) 
private Collection<Mission2Mission> children; 

@OneToMany(mappedBy = "parent", cascade=CascadeType.ALL) 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
private Collection<Mission2Mission> parents; 

Mission2Mission實體:

@ManyToOne 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
private Mission parent; 

@ManyToOne 
private Mission mission; 

這意味着,父母知道自己的孩子,反之亦然,但至少典型GSON#1應該使用的RetentionPolicy避免,因爲父母被排除在外。

我不知道這整個問題是否與JPA或GSON有關,但真正讓我懷疑的是,爲什麼這隻發生在服務器重新啓動後。它表明會出現某種會話問題,我找不出來,在這個特定問題上我還沒有發現任何其他線程或問題,所以我只是在這裏問。

我知道有懶惰和渴望的獲取類型,但使用它們不會解釋,爲什麼這個問題只出現在服務器重新啓動。

非常感謝, 凱

+0

添加fetchType.LAZY太所有的關係只是爲了安全起見:不工作:( –

回答

1

好吧,我終於找到了答案,這是一個痛苦的找出來:

在任務實體保持我在收藏的孩子和家長。但是,只有其中一個被GSON序列化,這個「父母」被排除(@GsonExclude = @Retention(RetentionPolicy.RUNTIME)& @Target(ElementType.FIELD),我剛纔明確提到它們是爲了澄清)。

下面的代碼是使命的實體的「錯誤」的版本:

@OneToMany(mappedBy = "mission", fetch=FetchType.LAZY, cascade=CascadeType.ALL)@XmlTransient 
private Collection<Mission2Mission> children; 

@OneToMany(mappedBy = "parent", fetch=FetchType.LAZY, cascade=CascadeType.ALL)@[email protected] 
private Collection<Mission2Mission> parents; 

是否ANY1別人看到這個問題? 「mappedBy」映射錯誤的引用。當然,當試圖檢索任務的孩子時,我需要將其映射到「父母」字段中,以便找到所有的條目,其中給定的任務是父母。這同樣適用於「父母」。檢索我需要找到的所有父母地圖Mission2Mission實體,其中「任務」(孩子)是這樣的。因爲Mission2Mission實體(參見上文)反過來並且(它真的排除了父代而不是子代),上面的代碼反過來也會導致可能的inf-loops。

交換映射字段(任務和父母)的工作就像一個魅力。花了很長時間才弄清楚。

感謝您的意見。緩存提示在這裏大大提高了調試速度:)

2

GSON不支持週期,所以這是最有可能的原因。我認爲在GSON中避免循環的正常方法是使變量瞬變,我沒有聽說過@Retention(RetentionPolicy.RUNTIME)工作,也許它確實...

您可能不會維護您的雙向關係這是非常錯誤的),所以在清除共享緩存之前不要有周期。

您也可以嘗試禁用緩存,或禁用編織來縮小問題的範圍。

您可能想嘗試其他JSON序列化程序,例如EclipseLink Moxy,它使用JAXB註釋並支持循環。

這裏有一個例子,http://java-persistence-performance.blogspot.com/2013/08/optimizing-java-serialization-java-vs.html

+0

禁用緩存導致重新啓動相同的行爲(哦,奇蹟) - 我真的想知道,我們沒有維護我們之間的關係,因爲我們真的試圖在每一個地方做到這一點。但是,這並不能解決問題,但只能提前揭示它。 我想知道爲什麼GSON仍然會運行到一個循環中,我已將@XmlTransient現在的關係,但這仍然沒有幫助。 –

相關問題