2013-08-29 31 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现在的关系,但这仍然没有帮助。 –

相关问题