Hibernate / Spring:即使在Service方法上使用@Transactional检索子集合之前,Session仍然关闭 [英] Hibernate/Spring: Session still closed before retrieval of child collection even with @Transactional on Service method

查看:169
本文介绍了Hibernate / Spring:即使在Service方法上使用@Transactional检索子集合之前,Session仍然关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



在这样的时间里,我想让你成为我最好的朋友。我正在使用hibernate 3.6.1 。使用session和spring 3.0.5.RELEASE和maven实现最终的JPA实现。所以maven项目被分成3个模块模块模块,服务模块和webapp模块。



其中是模型applicationContext的片段

 <! -  Transaction Management  - > 
< tx:注解驱动的事务管理器=transactionManager/>

< bean id =transactionManagerclass =org.springframework.orm.hibernate3.HibernateTransactionManager>
< property name =sessionFactoryref =sessionFactory/>
< / bean>

<! - 模型 - >
< bean id =genericDAOclass =com.blabla.blabla.model.dao.hibernate.HibernateGenericDAOImplabstract =true>
< property name =sessionFactoryref =sessionFactory/>
< / bean>



< bean id =contentclass =com.blabla.blabla.model.ContentImplscope =prototype/>

< bean id =contentDAOclass =com.blabla.blabla.model.dao.hibernate.ContentDAOImplparent =genericDAO>
< constructor-arg>
<值> com.blabla.blabla.model.ContentImpl< /值>
< / constructor-arg>
< / bean>

我也会在关系上给我一个噩梦的映射片段,所以我赢了' t转储所有内容:

  // ContentImpl 
@Id
@Column(name =CONTENT_ID )
私人长ID;
@Version
@Column(name =OBJ_VERSION)
private int version = 0;
// ....其他属性

@OneToMany(targetEntity = ContentImageImpl.class,cascade = {CascadeType.ALL},orphanRemoval = true)
@JoinColumn(name = CONTENT_ID,referencedColumnName =CONTENT_ID)
私人设置< 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布尔isDefault;
//没有其他关系


// ContentServiceImpl
public class ContentServiceImpl实现ContentService {
//从应用程序上下文连线
私有的ContentDAO contentDao;
private static Logger logger = Logger.getLogger(ContentServiceImpl.class);

@交易
公共列表<内容> getContentsbyCategoryID(Long categoryId){
return getContentDao()。getbyCategoryID(categoryId);
}


@交易
公共列表<内容> 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);
列表<内容> session = this.getSessionFactory()。getCurrentSession()。createCriteria(this.getPersistentClass())
.add(Restrictions.eq(category,(CategoryImpl)cat))
.setProjection(Projections。 distinct(Projections.id()))
.list();
logger.debug(session);
返回会话;
}

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

  org.hibernate.LazyInitializationException:未能懒惰地初始化一个角色集合:com.bla.bla.model.ContentImpl.contentFiles,没有会话或会话已关闭

真的很麻烦我唯一的临时解决方法是将这个关联标记为渴望获取,这是不合适的。我认为在服务方法之上的puttin @transactional会在没有打开时打开新会话吗?



请告知并感谢您阅读本文。

解决方案

交易的范围session)仅在 getContentsbyCategoryID()方法的周围。一旦你从它返回,交易将被提交并且会话关闭。它究竟在哪里抛出异常?它是否在 getContentsbyCategoryID()内的 list()操作中?或者,事实上,从 getContentsbyCategoryID()返回并试图在代码中的其他位置访问lazy集合之后呢?在这种情况下,您必须


  1. 增加交易的范围(并因此增加会话)

  2. 将获取类型更改为eager

  3. 手动将集合加载到 getContentsbyCategoryID()中(通过调用<$ c $例如c> size())
  4. 采用open-session-in-view模式(通过OpenSessionInViewFilter或OpenSessionInViewInterceptor) li>


Hello Spring/Hibernate Gurus!

in a time like this i would like you to be my best friends.I am working on a project using hibernate 3.6.1.Final JPA implementation using session and spring 3.0.5.RELEASE with maven.So with maven project is split in 3 modules model module, service module and webapp module.

where is snippet of the model applicationContext

       <!-- 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>

I will also put a snippet of the mapping on the relation giving me nightmares right now so i won't dump everything here:

//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;
}

so when assessing contentService.getContentbyCategoryId(longid) it throws

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

really bothers me the only temporal fix i did is to mark this association to eager fetch which am not ok with.I thought puttin @transactional on top of the service method would take care of opening new session when none is opened?

Please advise and thanks for reading this

解决方案

The scope of the transaction (and hence the session) is only around the getContentsbyCategoryID() method. Once you return from it, the transaction is committed and the session is closed. Where, exactly, is it throwing the exception? Is it on the list() operation inside getContentsbyCategoryID()? Or is it, in fact, after you have returned from getContentsbyCategoryID() and trying to access the lazy collection somewhere else in the code? In that case, you either have to

  1. increase the scope of the transaction (and, hence, the session)
  2. change fetch-type to eager
  3. manually load the collection in getContentsbyCategoryID() (by calling size() on it, for instance)
  4. Adopt the open-session-in-view pattern (either through the OpenSessionInViewFilter or the OpenSessionInViewInterceptor)

这篇关于Hibernate / Spring:即使在Service方法上使用@Transactional检索子集合之前,Session仍然关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆