2016-10-19 4 views
1

私は以下の問題を抱えています。私は@OneToManyエンティティ(以下のコード)の遅延読み込みセットを含むJPAエンティティを持っています。ここでSpring RESTコントローラ、トランザクション内デシリアライズ

@Entity 
@Table(name = "SKILL") 
public class Skill { 

    @Id 
    @Column(name = "SKILL_ID") 
    @GeneratedValue(generator = "increment") 
    @GenericGenerator(name = "increment", strategy = "increment") 
    private Long id; 

    @Column(name = "NAME") 
    private String name; 

    @ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE}) 
    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id") 
    @JsonIdentityReference(alwaysAsId=true) 
    private Skill parent; 

    @OneToMany(mappedBy="parent", cascade={CascadeType.ALL}) 
    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id") 
    @JsonIdentityReference(alwaysAsId=true) 
    private Set<Skill> children; 

    public Skill() { 

    } 

    // getters-setters ommitted 
} 

は春RESTコントローラからのコードです:

@RequestMapping(value = "/skill", method = RequestMethod.GET) 
public ResponseEntity<List<Skill>> listAllSkills() { 
    Iterable<Skill> skills = skillService.getAllSkills(); 
    return new ResponseEntity<>(Lists.newArrayList(skills), HttpStatus.OK); 
} 

私はこのコントローラからのエンティティを返すようにしようとするたびに、それは何が起こるか、私の知る限り理解されるように

JsonMappingException: failed to lazily initialize a collection of 
role: com.juriy.arcadia.domain.Skill.children, could not initialize 
proxy - no Session 

をスローしますジャクソンがトランザクション境界の外でエンティティの遅延ロードを試行しているのですから、セッションが見つからないのです。私は汚いハックを追加し、レイジーロードされたトランザクション内で、手動ことになっている部品を呼び出した場合、それが動作します:

@RequestMapping(value = "/skill", method = RequestMethod.GET) 
public ResponseEntity<List<Skill>> listAllSkills() { 

    Iterable<Skill> skills = skillService.getAllSkills(); 

    // Hack here: load required items inside of session bounds 
    for (Skill s : skills) { 
     System.out.println("Fetched skills: "+ s.getChildren().size()); 
     System.out.println("Fetched parent: "+ s.getParent()); 
    } 
    return new ResponseEntity<>(Lists.newArrayList(skills), HttpStatus.OK); 
} 

質問:は怠け者の場合にはデシリアライゼーションを整理するはずな方法は何ですか - 負荷とトランザクション。トランザクションの境界内でデシリアライゼーションを行う方法はありますか?

関連する質問:コントローラレイヤーを作成するのは良い方法ではないと聞きました@Transactional。この場合、トランザクションを設計する最良の方法は何ですか?

UPDATE:エンティティのEAGER荷重を加えることは、(そこに実体の大きな木だとEAGERロードは完全にパフォーマンスを殺すツリー全体をロードします)私の場合はオプションではありません。

答えて

0

すべてのスキルのリストを返そうとしている場合は、FetchType.EAGERを使用する必要があります。レイジーローディングは、データに直接アクセスすることなくデータをロードしません。だからあなたはそのエラーを持っています。

+0

残念ながら、オプションはありません。依存エンティティのグラフがあり、このアプローチはあまりにも多くの負荷をかけます。私は、トランザクションの境界をデシリアライゼーションが起こっているところまで広げようとしています。 – Juriy

1

ジャクソンはJPAトランザクションの外部で親のゲッターを呼び出しているため、遅延読み込みエンティティはもはや利用できません。

Fetch.EAGERに変更するか、アセンブラレイヤー(エンティティをPOJOに変換するレイヤー)を追加します。

それともこれが正しくトランザクションマネージャを設定していると仮定し

@Transaction 
@RequestMapping(value = "/skill", method = RequestMethod.GET) 
public ResponseEntity<List<Skill>> listAllSkills() { 
    Iterable<Skill> skills = skillService.getAllSkills(); 
    return new ResponseEntity<>(Lists.newArrayList(skills), HttpStatus.OK); 
} 

に@Transactionアノテーションを追加します。

+0

技術的な理由から、私はEAGERをフェッチすることはできません(親子関係で結ばれたエンティティの大きなグラフがあり、DB全体のスノーボールローディングが発生します)。 @Transactionalをメソッドまたはクラスレベルに置くことは、メソッドがデシリアライズの開始前に*を返すため、役に立たなかった。 – Juriy

+0

私はあなたに@トランザクションを指摘します。たぶん、JsonにHateosリンクを追加して、子エンティティが本当に遅れて読み込まれるようにする必要があります。その他のオプションは、データベースの負荷を軽減するハイバネート2次キャッシュを使用することです。 –

+0

私が思うに、メソッドを見て、メソッドに@Cacheアノテーションを追加し、Fetchtype.EAGERを作成してください。 https://www.mkyongを参照してください。com/spring/spring-caching-and-ehcache-example/ –

関連する問題