2

我知道这已经讨论过很多次了。我只是无法理解这是如何工作的或我的错误在哪里。
我认为给你一个简化的例子是向你展示我正在尝试做什么以及我正在采取什么假设的最佳方式......

我有一个带有名称的产品类。该名称是一个惰性的 String 属性。

我的道:

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,但我无法让它工作。您将如何将该拦截器添加到这个小示例中?

是否有任何代码错误或对它如何工作的误解?

你知道我可以下载任何简单的示例代码来检查它是如何工作的吗?

提前致谢, Neuquino

4

1 回答 1

6

问题是 HibernateInterceptor 从返回后关闭会话 ProductService getProduct()

来自API 文档

这个拦截器在方法调用之前将一个新的 Hibernate Session 绑定到线程,然后在有任何方法结果的情况下关闭并删除它。如果已经有一个预先绑定的 Session(例如来自 HibernateTransactionManager,或者来自周围的 Hibernate 拦截方法),拦截器只是参与其中。

并为以下调用打开一个新的ProductService.getProductName()。新创建的会话不知道您在上一个会话中从数据库中获取的产品实体。

您有多种解决此问题的方法:

1.) 添加一个急切加载名称的方法,并在特定上下文中使用它,这是 obviuos ;)

2.)您可以在Session.update(myProductEntity)调用之前将实体重新附加到活动会话Product.getName()ProductService.getProductName()

3.)您可以将其全部包装在包装方法调用ProductService.getProduct()ProductService.getProductName()参与的事务中。请参阅事务传播

4.) 在 Web 应用程序中,只要在控制器中创建视图,您就可以使用 OpenSessionInViewFilter 来保持会话打开

5.) 我认为你也可以直接使用 AOP。您可以让会话在任意连接点上保持打开状态,但我在那里没有真正的经验,不能更具体;)

希望有帮助...

于 2010-06-04T19:35:54.137 回答