430

私はこの問題を抱えています:

org.hibernate.LazyInitializationException: ロールのコレクションの遅延初期化に失敗しました: mvc3.model.Topic.comments、セッションまたはセッションが閉じられませんでした

モデルは次のとおりです。

@Entity
@Table(name = "T_TOPIC")
public class Topic {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @ManyToOne
    @JoinColumn(name="USER_ID")
    private User author;

    @Enumerated(EnumType.STRING)    
    private Tag topicTag;

    private String name;
    private String text;

    @OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
    private Collection<Comment> comments = new LinkedHashSet<Comment>();

    ...

    public Collection<Comment> getComments() {
           return comments;
    }

}

モデルを呼び出すコントローラーは次のようになります。

@Controller
@RequestMapping(value = "/topic")
public class TopicController {

    @Autowired
    private TopicService service;

    private static final Logger logger = LoggerFactory.getLogger(TopicController.class);


    @RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
    public ModelAndView details(@PathVariable(value="topicId") int id)
    {

            Topic topicById = service.findTopicByID(id);
            Collection<Comment> commentList = topicById.getComments();

            Hashtable modelData = new Hashtable();
            modelData.put("topic", topicById);
            modelData.put("commentList", commentList);

            return new ModelAndView("/topic/details", modelData);

     }

}

jsp ページは次のようになります。

<%@page import="com.epam.mvc3.helpers.Utils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
      <title>View Topic</title>
</head>
<body>

<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>

</c:forEach>
</ul>
</body>
</html>

jsp を表示すると、例外が発生します。c:forEachループの行で

4

32 に答える 32

236

Commentを取得するたびにすべての を表示したいことがわかっている場合はTopic、フィールドのマッピングを次のように変更しますcomments

@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();

コレクションはデフォルトで遅延ロードされます。詳細については、こちらをご覧ください。

于 2012-07-31T18:33:08.650 に答える
200

私の経験から、有名な LazyInitializationException を解決するには、次の方法があります。

(1) Hibernate.initialize を使用する

Hibernate.initialize(topics.getComments());

(2) JOIN FETCH を使用する

JPQL で JOIN FETCH 構文を使用して、子コレクションを明示的にフェッチできます。これは、EAGER フェッチに似ています。

(3) OpenSessionInViewFilter を使用する

LazyInitializationException はビューレイヤーでよく発生します。Spring フレームワークを使用している場合は、OpenSessionInViewFilter を使用できます。ただし、そうすることはお勧めしません。正しく使用しないと、パフォーマンスの問題が発生する可能性があります。

于 2012-08-01T07:26:07.177 に答える
92

私はそれが古い質問であることを知っていますが、私は助けたいです. 必要なサービス メソッドにトランザクション アノテーションを付けることができます。この場合、findTopicByID(id) は持つ必要があります。

@Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)

この注釈の詳細については、こちらを参照してください

その他のソリューションについて:

fetch = FetchType.EAGER 

は良い習慣ではありません。必要な場合にのみ使用してください。

Hibernate.initialize(topics.getComments());

hibernate イニシャライザは、クラスを hibernate テクノロジにバインドします。柔軟であることを目指している場合は、良い方法ではありません。

それが役に立てば幸い

于 2016-06-06T13:58:39.003 に答える
68

問題の原因:

デフォルトでは、休止状態はコレクション(関係)を遅延ロードします。つまりcollection、コード(クラスのherecommentsフィールドTopic)で使用するたびに、休止状態はデータベースからそれを取得します。問題は、コントローラーでコレクションを取得していることです(JPAセッションこれは、例外を引き起こすコード行です (commentsコレクションをロードしている場所):

    Collection<Comment> commentList = topicById.getComments();

コントローラー(終了した場所)で「コメント」コレクション(topic.getComments())を取得しJPA sessionているため、例外が発生します。また、次のcommentsようにjspファイルにコレクションを取得した場合(コントローラーで取得するのではなく):

<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>

同じ理由で同じ例外が引き続き発生します。

問題の解決:

FetchType.EagerEntity クラスでは (eagerly fetched コレクション) を使用してコレクションを 2 つしか持つことができないため、遅延読み込みは積極的に読み込むよりも効率的であるため、問題を解決するこの方法は、を単にFetchTypeeagerに変更するよりも優れていると思います。

コレクションを遅延初期化し、これを機能させたい場合は、次のコード スニペットを に追加することをお勧めしますweb.xml

<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

JPA sessionこのコードが行うことは、またはドキュメントの長さを増やすことです"to allow for lazy loading in web views despite the original transactions already being completed.".JPAセッションが少し長く開かれるように使用されているため、jspファイルとコントローラークラスにコレクションを遅延ロードできます. .

于 2015-07-17T18:30:25.423 に答える
37
@Controller
@RequestMapping(value = "/topic")
@Transactional

追加することでこの問題を解決します。これにより@Transactional、セッションを開くことができると思います

于 2016-12-14T11:02:20.843 に答える
29

その理由は、遅延読み込みを使用すると、セッションが閉じられるためです。

解決策は 2 つあります。

  1. 遅延ロードを使用しないでください。

    Set lazy=falsein XML または Set @OneToMany(fetch = FetchType.EAGER)In アノテーション。

  2. 遅延ロードを使用します。

    Set lazy=truein XML または Set @OneToMany(fetch = FetchType.LAZY)In アノテーション。

    あなたOpenSessionInViewFilter filterweb.xml

詳細 私のPOSTを参照してください。

于 2014-12-04T05:59:03.730 に答える
29

を処理する最善の方法LazyInitializationExceptionは、次のようにクエリ時にフェッチすることです。

select t
from Topic t
left join fetch t.comments

次のアンチパターンは常に避ける必要があります。

したがって、FetchType.LAZYクエリ時に、またはセカンダリ コレクション@Transactionalを使用して元のスコープ内で関連付けが初期化されていることを確認してください。Hibernate.initialize

于 2018-06-27T06:21:50.307 に答える
28

この問題は、休止状態のセッションを閉じた状態で属性にアクセスすることによって発生します。コントローラーに休止状態のトランザクションがありません。

可能な解決策:

  1. このロジックはすべて、コントローラーではなく、サービス層 (@Transactional を使用) で実行します。これを行う適切な場所が必要です。これは、コントローラーではなく、アプリのロジックの一部です (この場合、モデルを読み込むためのインターフェイス)。サービス層でのすべての操作は、トランザクションである必要があります。すなわち: この行を TopicService.findTopicByID メソッドに移動します。

    コレクション commentList = topicById.getComments();

  2. 'lazy' の代わりに 'eager' を使用してください。現在、「lazy」を使用していません..これは実際の解決策ではありません.lazyを使用したい場合は、一時的な(非常に一時的な)回避策のように機能します。

  3. Controller で @Transactional を使用します。ここでは使用しないでください。サービス レイヤーとプレゼンテーションを混在させているため、適切な設計ではありません。
  4. OpenSessionInViewFilterを使用してください。多くの欠点が報告されており、不安定になる可能性があります。

一般に、最適なソリューションは 1 です。

于 2017-02-13T14:17:16.177 に答える
20

コレクションを遅延ロードするには、アクティブなセッションが必要です。Web アプリでは、これを行う方法が 2 つあります。Open Session In Viewパターンを使用できます。このパターンでは、インターセプターを使用して、リクエストの開始時にセッションを開き、最後にセッションを閉じます。確実な例外処理が必要になるリスクがあります。そうしないと、すべてのセッションがバインドされてアプリがハングする可能性があります。

これを処理するもう 1 つの方法は、コントローラーで必要なすべてのデータを収集し、セッションを閉じてから、データをモデルに詰め込むことです。MVC パターンの精神に少し近いように見えるので、私は個人的にこのアプローチを好みます。また、この方法でデータベースからエラーが発生した場合は、ビュー レンダラーでエラーが発生した場合よりもはるかに適切に処理できます。このシナリオの友達はHibernate.initialize (myTopic.getComments()) です。また、リクエストごとに新しいトランザクションを作成しているため、オブジェクトをセッションに再アタッチする必要があります。そのために session.lock(myTopic,LockMode.NONE) を使用してください。

于 2012-07-31T20:13:23.063 に答える
7

@PersistenceContextasを宣言するとEXTENDED、この問題も解決することがわかりました。

@PersistenceContext(type = PersistenceContextType.EXTENDED)
于 2015-06-24T10:24:29.547 に答える
6

私の場合の問題を解決するには、この行が欠落しているだけでした

<tx:annotation-driven transaction-manager="myTxManager" />

アプリケーションコンテキストファイルで。

メソッドに対する@Transactional注釈は考慮されませんでした。

答えが誰かを助けることを願っています

于 2016-02-05T16:02:59.977 に答える
6

あなたのリストは遅延読み込みであるため、リストは読み込まれませんでした。リストに参加するための呼び出しは十分ではありません。リストを初期化するために Hibernate.initialize で使用します。リスト要素で動作しない場合は、それぞれに対して Hibernate.initialize を呼び出します。これは、トランザクション スコープから戻る前に行う必要があります。この投稿を見てください。
検索する -

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 
于 2012-07-31T20:11:56.403 に答える
5

コントローラーの @Transactional アノテーションがありません

@Controller
@RequestMapping("/")
@Transactional
public class UserController {
}
于 2016-03-26T10:30:47.723 に答える
4

JWT トークンを生成するメソッドを 2 回実行した後、このエラーが発生しました。

user.getUsersRole().stream().forEachOrdered((ur) -> roles.add(ur.getRoleId())); エラーを生成しました。

// MyUserDetails.java

@Service
public class MyUserDetails implements UserDetailsService {

  @Override
  public UserDetails loadUserByUsername(String email) {

    /* ERROR
    /* org.hibernate.LazyInitializationException: failed to 
    /* lazily initialize a collection of role: 
    /* com.organizator.backend.model.User.usersRole, 
    /* could not initialize proxy - no Session */
    user.getUsersRole().stream().forEachOrdered((ur) ->
           roles.add(ur.getRoleId()));

私の場合、@Transacctional注釈はそれを解決しました、

// MyUserDetails.java

import org.springframework.transaction.annotation.Transactional;

@Service
public class MyUserDetails implements UserDetailsService {

  @Override
  @Transactional // <-- added
  public UserDetails loadUserByUsername(String email) {

    /* No Error */
    user.getUsersRole().stream().forEachOrdered((ur) ->
           roles.add(ur.getRoleId()));

于 2021-09-05T13:51:18.890 に答える
2

Criteriaで作業している人にとって、私はそれを見つけました

criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);

必要なことはすべてやりました。

コレクションの初期フェッチ モードは、パフォーマンスを提供するために FetchMode.LAZY に設定されていますが、データが必要な場合は、その行を追加するだけで、完全に取り込まれたオブジェクトを楽しむことができます。

于 2015-12-01T05:22:43.877 に答える
0

私のSpring-Bootプロジェクトspring.jpa.open-in-viewでは、application.propertiesでfalseに設定されていました. true に設定すると問題が解決しました。

于 2021-12-27T17:43:30.430 に答える