【问题标题】:Understanding the SessionFactory in Spring了解 Spring 中的 SessionFactory
【发布时间】:2010-07-18 18:30:07
【问题描述】:

一点背景知识:我正在使用 Spring 和 Hibernate 创建一个非常简单的 domain/dao/service 结构。我还使用自动装配将我所有的 bean 注入他们快乐的地方。

在重构时,我最近在尝试访问我的休眠对象上的 FetchType.LAZY 属性时收到了非常流行的错误消息“无法初始化代理 - 无会话”。它是这样的:

public class Person {

...

 @ManyToOne(cascade = {}, fetch = FetchType.LAZY)
 @JoinColumn(name = "pet_id", nullable = false)
 public Pet getPet() {
  return pet;
 }
...
}

我曾经有一个访问 Pet 属性的 PersonService bean,并且这样做没有问题。但是,我最近重构了代码,以便 PersonH​​elper 不再查看 Pet,而是查看 Pet。虽然我的助手 bean 可以看到 PersonDao,可以拨打电话来获取该人,但由于我的会话已关闭,它无法访问 Pet。

所以,我想我不清楚我什么时候松开休眠会话。所有的配置看起来都很好,DAO 被注入到我的助手中,就像它过去被注入到我的服务中一样。我不确定为什么我的服务可以让宠物正常,但我的助手却不能。

非常感谢任何有助于理解这个“SessionFactory 之谜”的帮助。我意识到这可能是一个复杂的主题,所以指向一些好的阅读材料的链接会很有趣。

我已经将代码更改为 FetchType.EAGER(工作正常),但这个谜语在我的脑海中燃烧了一个整体:)。

根据请求,这里是(简化的)我的配置:

    <bean id="personSvc" class="org.comp.service.impl.PersonServiceImpl" />
    <bean id="personHelper" class="org.comp.service.helper.PersonHelper" />

    <bean id="personDao" class="org.comp.dao.hibernate.HibPersonDaoImpl">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
    </bean>

...

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <property name="packagesToScan" value="org.comp.domain"/>
        <property name="schemaUpdate" value="true" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">false</prop>

                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                </prop>
                <prop key="hibernate.cache.provider_configuration_file_resource_path">/hibernate-ehcache.xml</prop>
            </props>
        </property>
    </bean>
<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory">
        <ref bean="sessionFactory"/>
    </property>
</bean>

DAO 自动装配到帮助程序中:

@Autowired
private PersonDao personDao;

【问题讨论】:

    标签: java hibernate spring


    【解决方案1】:

    没有看到 PersonService 的代码/上下文配置,我只能猜测它为什么在重构之前起作用。如果您使用HibernateInterceptor 将会话管理包装在您的 DAO 方法周围,则会话在方法完成后立即关闭,除非它事先打开(例如通过OpenSessionInViewFilter)。

    我的猜测是HibernateInterceptor 的范围可能在重构期间发生了变化,因此会话现在在获取数据后立即关闭。您可能希望考虑扩展 HibernateInterceptor 的范围以涵盖您的服务/业务方法,以便会话保持足够长的时间以便延迟获取工作,或者使用OpenSessionInViewFilter,确保会话始终可用。

    【讨论】:

    • 非常有趣。我将研究过滤器,因为这是我不太了解的东西。
    • 添加了一些我正在使用的配置。 AnnotationSessionFactoryBean 可能看起来有点奇怪,因为我试图为这篇文章简化这个想法(实际上它有点复杂)
    • @Stephano - 感谢您的更新。我猜你的 DAO 是使用 HibernateDaoSupport 实现的?从这里的细节来看,我看不出它以前会如何工作。你可能只是幸运! (或者更现实地说,还有更多细节可以解开谜团。例如,是否有任何类型的事务管理?)可能是您的 DAO 正在调用其他 DAO,因此会话在第一个期间保持打开状态调用,它跨越嵌套调用。相关:stackoverflow.com/questions/2145024/…
    • 我认为你成功了。我正在进行一些 AOP(我还不太明白)。似乎因为我的服务不包括在内,所以事情没有奏效。我需要去谷歌 BeanNameAutoProxyCreator... 但感谢您的所有帮助:) .
    • AOP 是要走的路——有些人认为 HibernateDaoSupport 已经过时了。 AOP 需要更多的“脑力投资”,但它的回报非常灵活。
    【解决方案2】:

    OSIV 始终是必读的,无论您是否正在编写基于 Web 的应用程序。

    我在我的 Spring bean 的方法 (at the service layer) 中使用了@Transactional 标记,并让 Spring 以这种方式为我管理会话(默认情况下,Spring 为每个线程处理 Hibernate 的会话)。

    【讨论】:

      猜你喜欢
      • 2014-06-14
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多