ここでスタック上の最初の質問ですので、優しくしてください:D
休止状態のOneToMany関係を作成しようとしています。 DBからデータを取得しようとすると、StackOverflowErrorが発生します。しかし、OneToManyパーツを削除すると、すべてが正常に実行されます。これはmy RESTサービスの一部であり、現時点ではVMware vFabric ServerおよびMySQL DBで実行されます。
フェッチの例:
_@Inject
private EntityManager entityManager;
...
entityManager.find(League.class, 1);
...
entityManager.find(Team.class, 1);
_
MySQLスクリプト:
_CREATE TABLE league (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE team (
team_id int(11) NOT NULL AUTO_INCREMENT,
name varchar(20) COLLATE utf8_unicode_ci NOT NULL,
fk_leagueId int(11) NOT NULL,
PRIMARY KEY (team_id),
FOREIGN KEY (fk_leagueId) REFERENCES league(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
_
クラス:
_@XmlRootElement
@Entity
@Table(name = "team")
@Data
public class Team {
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
@Column(name = "team_id")
private int id;
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fk_leagueId", nullable = false)
private League league;
}
@XmlRootElement
@Entity
@Table(name = "league")
@Data
public class League {
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
//if I comment 2 lines below, there is no error, and everything works fine
@OneToMany(fetch = FetchType.LAZY, mappedBy = "league")
private Set<span><</span>Team> teams;
}
_
エラー:
_Hibernate: select league0_.id as id1_1_0_, league0_.name as name2_1_0_ from league league0_ where league0_.id=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Exception in thread "Tomcat-http--3" Java.lang.StackOverflowError
at org.jboss.logging.JDKLogger.translate(JDKLogger.Java:73)
at org.jboss.logging.JDKLogger.isEnabled(JDKLogger.Java:85)
at org.jboss.logging.JDKLogger.doLog(JDKLogger.Java:41)
at org.jboss.logging.Logger.debug(Logger.Java:406)
at org.hibernate.internal.CoreMessageLogger_$logger.debug(CoreMessageLogger_$logger.Java:525)
at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.Java:104)
at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.Java:95)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.Java:180)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.Java:159)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.Java:1858)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.Java:1835)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.Java:1815)
at org.hibernate.loader.Loader.doQuery(Loader.Java:899)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.Java:341)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.Java:311)
at org.hibernate.loader.Loader.loadCollection(Loader.Java:2234)
at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.Java:65)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.Java:674)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.Java:83)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.Java:1849)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.Java:549)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.Java:234)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.Java:545)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.Java:124)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.Java:428)
at com.lukaszb.motspe.webapp.model.League.hashCode(League.Java:21)
at com.lukaszb.motspe.webapp.model.Team.hashCode(Team.Java:20)
at Java.util.HashMap.hash(HashMap.Java:351)
at Java.util.HashMap.put(HashMap.Java:471)
at Java.util.HashSet.add(HashSet.Java:217)
...
_
編集:
@Thiharaと@KarIPのおかげで、これを解決できました。チームとリーグのtoString()を次のようにオーバーライドしました:
_@Override
public String toString() {
return "League [id=" + id + ", name=" + name + "]";
}
@Override
public String toString() {
return "Team [id=" + id + ", name=" + name + "]";
}
_
必要に応じてDBからデータを取得できました。しかし、その後、解析中に無限のサイクルでJAXBエラーが発生しました。だから私は@XmlAccessorType(XmlAccessType.FIELD)
でTeamとLeagueクラスに注釈を付けたので、メソッドとTeam league
フィールドを_@XmlTransient
_と見ないので、解析されません。
ここでは、toString()実装を削除することもできますが、それでも動作します。理由は完全にはわかりません。問題は解決しましたが、より正確な説明を聞きたいです。 DB通信プロセス全体の後(またはそうではない場合でも)JAXBがデータフェッチを停止した理由はわかりません。具体的には、ジャージーを使用しています。
_@GET
@Path("search/id")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<League> searchById(@QueryParam("id") int id) {
return Arrays.asList(leagueDAO.getById(id));
}
_
StackOverFlowをスローできる唯一の方法は、チームのリーグに再帰的にアクセスする場合です。
チームからリーグへチームからリーグへ
オブジェクトを反射的または再帰的に他の表現に変換して、無限ループを発生させようとする関数があると思います。
よく似た問題がありました。モデルオブジェクトでLombokの_@Data
_注釈を使用して、ゲッター、セッター、およびその他の標準メソッドを自動生成しました。 Lombokによって生成されたtoString()
メソッドは、Team
とLeague
オブジェクトの間に循環依存関係を導入したと思います。 League
オブジェクトから_Set<teams> teams
_を取得しようとすると、SpringがロギングのためにtoStringメソッドを呼び出していたため、_Java.lang.StackOverflowError
_を取得しました。
LombokのtoString()
メソッドを取り除くことでこれを解決しました。 _@Data
_注釈をLombokの_@Getter
_および_@Setter
_注釈に置き換えました。そうすれば、toString()
メソッドを取得しなくても、無料のゲッターとセッターの恩恵を受けることができます。
_@Data
_複雑な注釈を使用する場合、循環依存関係はLombok'stoString()
自動生成メソッドから発生します。特定のフィールドの循環依存関係を除外するには:
_@Entity
@Data
public class Team {
...
@ToString.Exclude
@ManyToOne
private League league;
}
_
私にとっては、Lombokが提供するhashCodeとtoStringのデフォルト実装の両方がこの問題の原因でした。
この注釈を使用して、1つの注釈でequalsAndHasCodeの両方のメンバーを除外できます。
@EqualsAndHashCode(exclude = {"certificates", "payment"})
また、equalsメソッドからメンバーだけを除外する場合、Lombokは次を提供します:@ToString.Exclude
@ToString.Exclude
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "shipment")
private Set<Certificate> certificates;
私は同様の問題を抱えていましたが、私の場合、これは何の助けにもなりませんでした。
この1つのアプローチを支援しました。
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "order_id")
@Fetch(value = FetchMode.SUBSELECT)
private List<Product> orderLines;
name = "order_id"はProductテーブルの外部キー列です。
そして、Productエンティティには何も入れませんでした。
このエラーが発生したのは、Jacksonを使用して@OneToMany
および@ManyToOne
の両側にマッピングされたオブジェクトのリストを解析して、無限ループを引き起こしたためです。
同じ状況にある場合は、@JsonManagedReference
および@JsonBackReference
注釈を使用してこれを解決できます。
APIからの定義:
JsonManagedReference( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):
注釈付きプロパティがフィールド間の双方向リンケージの一部であることを示すために使用される注釈。そして、その役割は「親」(または「フォワード」)リンクです。プロパティの値タイプ(クラス)には、JsonBackReferenceアノテーションが付けられた単一の互換性のあるプロパティが必要です。リンケージは、このアノテーションが付けられたプロパティが通常どおりに処理されるように処理されます(通常はシリアル化され、逆シリアル化のための特別な処理は行われません)。特別な処理が必要なのは、一致する後方参照です
JsonBackReference:( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):
関連するプロパティがフィールド間の双方向リンケージの一部であることを示すために使用される注釈。そしてその役割は「子」(または「戻る」)リンクです。プロパティの値の型はBeanである必要があります。Collection、Map、Array、または列挙型にすることはできません。リンケージは、このアノテーションが付けられたプロパティがシリアル化されないように処理されます。そして、逆シリアル化中に、その値は「管理された」(フォワード)リンクを持つインスタンスに設定されます。
例:
Owner.Java:
@JsonManagedReference
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
Set<Car> cars;
Car.Java:
@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;
別の解決策は、フィールドにnullを設定する@JsonIgnore
を使用することです。