【问题标题】:Help needed with Spring/Hibernate Lazy-loadingSpring/Hibernate 延迟加载需要帮助
【发布时间】:2011-02-27 22:42:17
【问题描述】:

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

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

是否存在任何代码错误或对它的工作原理的误解?

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

提前致谢, 内基诺

【问题讨论】:

    标签: hibernate spring lazy-loading interceptor


    【解决方案1】:

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

    来自API DOCs

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

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

    您有多种解决方法:

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

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

    3.) 您可以将其全部包装在一个事务中,该包装方法调用ProductService.getProduct()ProductService.getProductName() 参与。参见Transaction Propagation

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

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

    希望对您有所帮助...

    【讨论】:

      猜你喜欢
      • 2011-10-25
      • 1970-01-01
      • 2011-09-24
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 2012-01-24
      • 1970-01-01
      相关资源
      最近更新 更多