Spring/Hibernate Lazy-loading需要帮助

Neu*_*ino 2 spring hibernate lazy-loading interceptor

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

我有一个名称的Product类.该名称是一个惰性的String属性.

我的DAO:

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

我的服务界面:

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);
}
Run Code Online (Sandbox Code Playgroud)

我的服务实施:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的主要课程:

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;
    }
Run Code Online (Sandbox Code Playgroud)

我的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>
Run Code Online (Sandbox Code Playgroud)

异常片段:

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)
Run Code Online (Sandbox Code Playgroud)

如果我假设HibernateInterceptor在不同的调用中保持Hibernate会话打开,我是对的吗?如果我是这样,为什么会在加载产品对象后关闭会话?

我在某处读到了我也可以使用OpenSessionInViewInterceptor,但我无法使其工作.你会如何将这个拦截器添加到这个小例子中?

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

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

在此先感谢Neuquino

fas*_*seg 6

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

来自API DOC:

这个拦截器在方法调用之前将新的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.你可以有一个方面让会话在一个任意的Joinpoint上打开,但我没有真正的经验,并且不能更具体;)

希望有帮助......