【问题标题】:Hibernate/Spring: Session still closed before retrieval of child collection even with @Transactional on Service methodHibernate / Spring:即使在Service方法上使用@Transactional,在检索子集合之前会话仍然关闭
【发布时间】:2012-02-14 10:01:23
【问题描述】:

你好 Spring/Hibernate 大师!

在这样的时刻,我希望你成为我最好的朋友。我正在使用 hibernate 3.6.1 开发一个项目。使用 session 和 spring 3.0.5.RELEASE 和 maven 的最终 JPA 实现。所以使用 maven 项目是分为模型模块、服务模块和webapp模块3个模块。

模型applicationContext的sn-p在哪里

       <!-- Transaction Management    -->
<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<!-- Model -->
<bean id="genericDAO" class="com.blabla.blabla.model.dao.hibernate.HibernateGenericDAOImpl" abstract="true">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>



<bean id="content" class="com.blabla.blabla.model.ContentImpl" scope="prototype" />

<bean id="contentDAO" class="com.blabla.blabla.model.dao.hibernate.ContentDAOImpl" parent="genericDAO">
    <constructor-arg>
        <value>com.blabla.blabla.model.ContentImpl</value>
    </constructor-arg>
</bean>

我还将在关系上放一个映射的 sn-p,现在让我做噩梦,所以我不会在这里倾倒所有东西:

//ContentImpl
@Id
@Column(name = "CONTENT_ID")
private Long ID;
@Version
@Column(name = "OBJ_VERSION")
private int version = 0;
//.... other properties

@OneToMany(targetEntity = ContentImageImpl.class,cascade = {CascadeType.ALL},orphanRemoval = true)
@JoinColumn(name = "CONTENT_ID", referencedColumnName = "CONTENT_ID")
private Set<ContentImage> images = new HashSet<ContentImage>();

//ContentImageImpl
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CONTENT_IMAGE_ID")
private Long ID;

@Column(name = "PATH")
private String path;

@Column(name ="IS_DEFAULT")
private Boolean isDefault;
//no other relations


//ContentServiceImpl
 public class ContentServiceImpl implements ContentService {
//wired from application context
private ContentDAO contentDao;
private static Logger logger = Logger.getLogger(ContentServiceImpl.class);

@Transactional
public List<Content> getContentsbyCategoryID(Long categoryId) {
    return getContentDao().getbyCategoryID(categoryId);
}


@Transactional
public List<Content> getContentsWithImagesbyCategoryID(Long categoryId) {
//return getContentDao().getbyCategoryID(categoryId);
    return getContentDao().getWithImagesbyCategoryID(categoryId);



//ContentDAOImpl
 public List<Content> getbyCategoryID(Long category_id) {
    Category cat = modelManager.createCategory();
    cat.setID(category_id);
    logger.info("calling  getbyCategoryID");
    logger.debug(category_id);
    List<Content> session =  this.getSessionFactory().getCurrentSession().createCriteria(this.getPersistentClass())
            .add(Restrictions.eq("category",(CategoryImpl)cat))
            .setProjection(Projections.distinct(Projections.id()))
            .list();
    logger.debug(session);
    return session;
}

所以当评估contentService.getContentbyCategoryId(longid) 它抛出

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of  role: com.bla.bla.model.ContentImpl.contentFiles, no session or session was closed

真的让我很困扰,我做的唯一临时修复是将此关联标记为不适用的渴望获取。我认为在服务方法顶部放置 @transactional 会在没有打开新会话时负责打开新会话?

请告知并感谢您阅读本文

【问题讨论】:

    标签: hibernate spring session spring-mvc lazy-loading


    【解决方案1】:

    渲染视图时会发生这种情况吗? 如果是这种情况,您可能需要考虑使用 Spring 的 OpenSessionInViewFilter。这会将 Session 绑定到线程以完成请求的整个处理。如果使用 JPA,您可以使用 OpenEntityManagerInViewFilter

    在您的 web.xml 中:

    <filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>sessionFactoryBeanName</param-name>
            <param-value>sessionFactory</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    【讨论】:

      【解决方案2】:

      事务(以及会话)的范围仅围绕getContentsbyCategoryID() 方法。一旦你从它返回,事务就被提交并且会话被关闭。确切地说,它在哪里抛出异常?是在getContentsbyCategoryID() 内部的list() 操作上吗?或者实际上是在您从getContentsbyCategoryID() 返回并尝试在代码中的其他位置访问惰性集合之后?在这种情况下,您要么必须

      1. 增加事务的范围(从而增加会话)
      2. 将 fetch-type 更改为 eager
      3. getContentsbyCategoryID() 中手动加载集合(例如,通过在其上调用size()
      4. 采用 open-session-in-view 模式(通过 OpenSessionInViewFilter 或 OpenSessionInViewInterceptor)

      【讨论】:

      • 您好,谢谢您的解释,这更清楚了。我正在从getContentsbyCategoryID() 返回的列表中访问每个对象的惰性集合。我正在尝试你的 openSessioninViewFilter 但没有工作,因为我得到了相同的结果
      猜你喜欢
      • 2011-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-10
      • 1970-01-01
      • 2018-02-13
      • 2016-07-03
      • 1970-01-01
      相关资源
      最近更新 更多