2012-03-08 13 views
0

私はこの方法でステートレスセッションBeanがあります。このように定義されている場合JPA 2で 'はセッションまたはセッションが閉じなかった' とEJB 3.1

@Override 
public List<Character> getUserCharacters(int userId) { 
    User user = em.find(User.class, userId); 
    if(user != null) 
     return user.getCharacters(); 
    else 
     return null; 
} 

Userクラス:

@Entity 
@Table(name="Users") 
public class User implements Serializable{ 

    /** */ 

private static final long serialVersionUID = 8119486011976039947L; 

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

@ManyToMany(fetch=FetchType.EAGER) 
private Set<Role> roles; 

@OneToMany(mappedBy="owner",fetch=FetchType.LAZY) 
private List<com.AandP.game.model.characters.Character> characters; 

public User() { 
    creationDate = new Date(); 
    roles = new HashSet<Role>(); 
    } 
} 

しかし、このメソッドを実行すると(私の@Named beanから)、私は例外を受け取ります:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.AandP.game.model.User.characters, no session or session was closed 

o JPA 2.0仕様セッションは、トランザクション全体で生き続ける必要があります。この状況では、トランザクションは(私の意見では)メソッド呼び出し全体の最後になります(クラスまたはメソッドに追加のトランザクション属性はありません)。

このコードで何が問題になっているのですか?クラスプロパティを怠け者で読み込むにはどうすればよいですか。

答えて

0

@TransactionAttributeを指定する必要があります。これにより、メソッドがトランザクション型になります。それ以外の場合は、各エンティティマネージャの操作ごとに読み取り専用トランザクションと新しい基本セッションが開始されます。これは、遅延コレクションと組み合わせると、コレクションを取得すると元のセッションが閉じられることを意味します。

+0

「TransactionAttributeType」はどちらを使用しますか?Javadocsは次のように述べています:TransactionAttributeアノテーションが指定されておらず、Beanがコンテナ管理のトランザクション境界を使用している場合、REQUIREDトランザクション属性のセマンティクスが仮定されます。_したがって、TransactionAttributeアノテーションを付けないアノテーションメソッドはOKです。 – pWoz

+0

Bozhoあなたはそれを説明できますか? – pWoz

+0

いいえ:)読取り専用トランザクションに言及する別の節があるかもしれません。しかし、TransactionAttributeを追加することはできますか? – Bozho

1

According to the JPA 2.0 specification session should stay alive for a whole transaction. In this situation transaction (in my opinion) last for a whole method call (there is no additional transaction attributes on class or method).

これは当てはまりますが、返されたオブジェクトのシリアル化は含まれません。

セッションBeanをWebサービスとしてエクスポートするのと同じ問題がありました。問題の詳細についてはhereをご覧ください。

同様の使い方をしているなら、エンティティではなく普通のオブジェクトを返すことを強くお勧めします。私たちのようにいくつかのBeanマッピングフレームワークを使用することができます。我々はDozerを使用しました。

0

pWoz:Bozhoが言うことは正しいです。私が追加する1つの注意点は、インターフェース(ローカルまたはリモート)を介してそのメソッドに入っていない場合、その注釈は重要ではないということです。これはあなたのBeanがどのように見えるかである場合は、次の理由は、同じセッションBean内で表彰するつもりはないの属性

@Stateless 
public class MyUserBean implements UserBeanLocal { 
... 

    public void doSomeStuffWithUserCharactersById(int id) { 
    List<Character>userCharacters = getUserCharacters(id); 
    } 

    @Override 
    @TransactionAttribute(TransactionAttributeType.REQUIRED) 
    public List<Character> getUserCharacters(int userId) { 
    User user = em.find(User.class, userId); 
    if(user != null) 
    return user.getCharacters(); 
    else 
    return null; 
    } 
} 

、呼び出された最初のビジネスメソッドは、トランザクションコンテキストと動作を決定します。さて、私はソースコードの残りの部分が見えないので、このインスタンスで何が起こっているのかはっきりとは分かりませんが、それは非常に一般的な間違いです。

+0

私はインターフェイスを通してこのメ​​ソッドに入ります。 'getUserCharacters(int userId)'はこのクラスの唯一のメソッドであり、このクラスはステートレスセッションBeanです。 – pWoz

+0

私もいくつかの調査を行いました。 'user.getCharacters()を返す前に' user.getCharacters()。size() 'を追加するとすべて正常に動作します。だから私の意見では、この例のreturn文は 'User'クラスの' characters'コレクションを初期化しません。私は、Hibernateにリストの初期化を強制するために、このコレクションのどのメソッドも呼び出さなければなりません。しかし、例外はかなり誤解を招く。 – pWoz

0

2013年7月24日19:47:07387 ERROR: - 怠惰な役割のコレクションの初期化に失敗しました:セッションまたはセッションがnull閉鎖された無com.xxxx.domain.DenialMaster.denialDetailsを、

私の設定:

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

<bean id="transactionManagerDL" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="emfDL" /> 
</bean> 

<bean id="emfDL" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dataSourceDL" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
    </property> 
    <property name="mappingResources"> 
     <value>META-INF/orm.xml</value> 
    </property> 
    <property name="packagesToScan" value="${dl.entity.packages}" /> 
    <property name="jpaProperties"> 
     <props> 
      <prop key="hibernate.dialect">${catalog.org.hibernate.dialect}</prop> 
      <prop key="hibernate.max_fetch_depth">${catalog.org.hibernate.jdbc.max.fetchdepth}</prop> 
      <prop key="hibernate.jdbc.fetch_size">${catalog.org.hibernate.jdbc.fetchsize}</prop> 
      <prop key="hibernate.jdbc.batch_size">${catalog.org.hibernate.jdbc.batchsize}</prop> 
      <prop key="hibernate.show_sql">${catalog.org.hibernate.showsql}</prop> 
      <prop key="hibernate.connection.autocommit">${catalog.org.hibernate.connection.autocommit} 
      </prop> 

     </props> 
    </property> 
</bean> 

SOLUTION:@Transactional(読み取り専用=真) 例を追加ServiceImplあなたのクラスで :

@Override 
@Transactional(readOnly = true) 
public YourBean findById(long id) throws Exception { 
    return yourDAO.findOne(id); 
} 

をし、 @LazyCollection(LazyCollectionOption.FALSE):

@OneToMany(fetch=FetchType.LAZY) 
    @JoinColumn(name = "idMaster") 
    @LazyCollection(LazyCollectionOption.FALSE) 
    public List<DenialDetail> getDenialDetails() { 
    return denialDetails; 
    } 
関連する問題