2

私はこれが何度も議論されてきたことを知っています。これがどのように機能するのか、どこに間違いがあるのか​​ 理解できません。
私がやろうとしていることと、私が取っている仮定を示す最良の方法は、縮小された例を示すことだと思います...

名前付きの Product クラスがあります。名前は遅延型の String プロパティです。

私のDAO:

public abstract class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO
{
    public List getAll()
    {
        return this.getHibernateTemplate().find("from " + this.getDomainClass().getSimpleName());
    }
}

マイ サービス インターフェイス:

public interface ProductService {
    //This methods are Transactional, but same exception error is thrown if there weren't
    @Transactional
    public Product getProduct();
    @Transactional
    public String getName(Product tp);
}

私のサービスの実装:

public class ProductServiceImpl implements ProductService  {
    private ProductDAO productDAO;
    public Product getProduct() {
        List ps = this.productDAO.getAll();
        return (Product) ps.get(0);
    }
    public String getName(Product p){
        return p.getName();
    }
}

私のメインクラス:

public class Main {
    private ProductService productService;
    public static void main(String[] args) {
        Main main= new Main();          
        main.productService= (ProductService)(new ClassPathXmlApplicationContext("applicationContext.xml")).getBean("productProxy");
        //load the product without the name
        Product p = main.productService.getProduct();
        //load the lazy name
        System.out.println(main.productService.getName(p));  //EXCEPTION IS THROWN IN THIS LINE
    }
    public void setProductService(ProductService productService) {
        this.productService= productService;
    }

    public ProductService getProductService() {
        return productService;
    }

私のapplicationContext.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:util="http://www.springframework.org/schema/util"
   xmlns:jee="http://www.springframework.org/schema/jee"
   xmlns:lang="http://www.springframework.org/schema/lang"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:sca="http://xmlns.oracle.com/weblogic/weblogic-sca">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value></property>
        <property name="url"><value>jdbc:oracle:thin:@${hostname}:${port}:${schema}</value></property>
        <property name="username"><value>${username}</value></property>
        <property name="password"><value>${password}</value></property>
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource"><ref local="dataSource"/></property>
        <property name="configLocation"><value>hibernate.cfg.xml</value></property>
        <property name="configurationClass"><value>org.hibernate.cfg.AnnotationConfiguration</value></property>
    </bean>

    <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>

    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory"><ref bean="sessionFactory"/></property>
        <property name="allowCreate" value="true"/>
    </bean> 
    <bean id="productDAO" class="product.model.data.ProductDAO" >
        <property name="sessionFactory" ref="sessionFactory"/>
</bean>
    <bean id="hibernateInterceptor"
      class="org.springframework.orm.hibernate3.HibernateInterceptor">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>
    <bean id="productService"
      class="product.services.ProductServiceImpl">
        <property name="productDAO">
            <ref bean="ProductDAO"/>
        </property>
    </bean>
    <bean id="productProxy"
      class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target">
             <ref bean="productService"/>
        </property>
        <property name="proxyInterfaces">
             <value>product.services.ProductService</value>
        </property>
        <property name="interceptorNames">
            <list>
                <value>hibernateInterceptor</value>
            </list>
        </property>
    </bean>
</beans>

例外フラグメント:

11:59:57,775 [main] DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils  - Opening Hibernate Session
11:59:57,775 [main] DEBUG org.hibernate.impl.SessionImpl  - opened session at timestamp: 12749723977
11:59:57,777 [main] ERROR org.hibernate.LazyInitializationException  - could not initialize proxy - no Session 
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:108)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:150)
    at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)

HibernateInterceptor がさまざまな呼び出しの間で Hibernate セッションを開いたままにしていると仮定しても、私は正しいですか? もしそうなら、製品オブジェクトを読み込んだ後にセッションが閉じられるのはなぜですか?

OpenSessionInViewInterceptor も使用できることをどこかで読みましたが、機能させることはできません。この小さな例にそのインターセプターをどのように追加しますか?

これがどのように機能するかについて、コードの間違いや誤解はありますか?

これがどのように機能するかを確認するためにダウンロードできる簡単なサンプルコードを知っていますか?

前もってありがとう、ネキノ

4

1 に答える 1

6

問題は、HibernateInterceptor がセッションから戻った後にセッションを閉じることです。 ProductService getProduct()

API DOCから:

このインターセプターは、メソッド呼び出しの前に新しい Hibernate Session をスレッドにバインドし、メソッドの結果が発生した場合に後でそれを閉じて削除します。事前にバインドされたセッション (HibernateTransactionManager から、または周囲の Hibernate インターセプト メソッドから) が既に存在する場合、インターセプターは単にそれに参加します。

への次の呼び出しのために新しいものを開きますProductService.getProductName()。新しく作成されたセッションには、前のセッションで DB から取得した製品エンティティに関する知識がありません。

これを解決するには、さまざまな可能性があります。

1.) 名前を熱心にロードするメソッドを追加し、特定のコンテキストでそれを使用します。これは明らかです;)

Session.update(myProductEntity)2.) を呼び出す前にProduct.getName()、エンティティをアクティブなセッションに再接続できます。ProductService.getProductName()

ProductService.getProduct()3.) ラップされたメソッドが呼び出してProductService.getProductName()参加するトランザクションですべてをラップできます。トランザクションの伝播を参照してください。

4.) Web アプリケーションでは、コントローラーでビューが作成される限り、OpenSessionInViewFilter を使用してセッションを開いたままにすることができます。

5.) AOP を直接使用することもできると思います。任意のジョインポイントでセッションを開いたままにするアスペクトを持つことができますが、私は実際の経験がなく、より具体的にすることはできません;)

それが役に立ったことを願っています...

于 2010-06-04T19:35:54.137 に答える