0

JPAとHibernateでSpringを使用しています。@Repositoy で注釈が付けられた DAO クラスといくつかのコントローラー クラスがあります。コントローラーでdaoのメソッドの1つを呼び出していくつかのエンティティをロードすると、エンティティが返され、その後、最初にロードされたエンティティのフィールドに格納されている他のエンティティを取得したいと考えています。しかし、その時点で、春はすでにセッションを閉じており、遅延読み込みはできなくなりました。

私の db.xml 構成:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" default-autowire="byName">

    <!-- Scans within the base package of the application for @Components to configure as beans -->
    <bean id="placeholderConfig"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:db.properties" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="jpaVendorAdapter" />
    </bean> -->
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
                <property name="databasePlatform" value="${db.dialect}" />
            </bean>
        </property>     
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${db.driver}" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.username}" />
        <property name="password" value="${db.password}" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
</beans>

Dao のメソッドには、次のように注釈が付けられています。

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

今、私はこのようなことをしたい:

@Controller
public class HomeController{

    @Autowired
    private UserDao userDao;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ResponseEntity<String> home(){
        ...
        User user = userDao.findUser(id);
        Set<Order> orders = user.getOrders();
        ...
    String myResult = ...;
    return jsonService.generateResponse(myResult);
    }

}

@Repository
public class UserDao{

    @PersistenceContext
    private EntityManager entityManager;

    public User findUser(Integer id){
        return entityManager.find(User.class, id);
    }
}

一連の注文は遅延ロードする必要がありますが、次の例外が発生します: org.springframework.web.util.NestedServletException: Request processing failed; ネストされた例外は org.hibernate.LazyInitializationException: ロールのコレクションを遅延初期化できませんでした:...,セッションがないか、セッションが閉じられませんでした

根本原因: org.hibernate.LazyInitializationException: ロールのコレクションを遅延初期化できませんでした: ...、セッションまたはセッションが閉じられませんでした

Controller wirt @Transactional でメソッドに注釈を付けようとし、db.xml の注釈駆動型プロパティに mode="aspectj" を設定しようとしましたが、何も機能しませんでした。ユーザーの注文を遅延ロードする方法はありますか?

ご不明な点がございましたら、どうぞよろしくお願いいたします。

4

1 に答える 1

5

特別なフィルターを使用して、Web ビューでセッションを取得できます。web.xml に追加

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

フィルターは次のように機能します。

  • フィルタがサーブレット リクエストをインターセプトする
  • フィルターは EntityManager を開き、それを現在のスレッドにバインドします
  • Webコントローラーが呼び出されます
  • Web コントローラー呼び出しサービス
  • トランザクション インターセプターは、新しいトランザクションを開始し、スレッド バインドされた EntityManager を取得して、それをトランザクションにバインドします。
  • サービスが呼び出され、EntityManager で何らかの処理を行ってから、戻ります
  • トランザクション インターセプターが EntityManager をフラッシュしてから、トランザクションをコミットします。
  • Web コントローラーはビューを準備してから返します
  • ビューが構築されます
  • フィルターは EntityManager を閉じ、現在のスレッドからアンバインドします
于 2013-06-25T17:31:39.290 に答える