Hibernate/Spring:即使在 Service 方法上使用 @Transactional,会话在检索子集合之前仍然关闭
Spring/Hibernate 专家您好!
在这样的时刻,我希望你成为我最好的朋友。我正在使用 hibernate 3.6.1 开发一个项目。使用 session 和 spring 3.0.5 最终 JPA 实现。使用 maven 发布。所以使用 maven 项目分为 3 个模块模型模块、服务模块和webapp模块。
模型 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>
我还将在关系上放置一个映射片段,现在给我带来噩梦,所以我不会在这里转储所有内容:
//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 放在服务方法之上会在没有打开任何会话时负责打开新会话?
请提供建议并感谢您阅读本文
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
渲染视图时会发生这种情况吗?
如果是这种情况,您可能需要考虑使用 Spring 的
OpenSessionInViewFilter
。这会将会话绑定到线程以完成请求的整个处理。如果使用 JPA,您可以使用 OpenEntityManagerInViewFilter。在您的 web.xml 中:
Does this happen when rendering the view?
If it is the case you might want to consider using Spring's
OpenSessionInViewFilter
. This will bind the Session to the thread for the entire processing of the request. If using JPA you can useOpenEntityManagerInViewFilter
.In your web.xml:
事务(以及会话)的范围仅围绕
getContentsbyCategoryID()
方法。一旦您从其中返回,事务就会被提交并且会话将被关闭。它到底在哪里抛出异常?是在getContentsbyCategoryID()
内的list()
操作上吗?或者实际上是在您从 getContentsbyCategoryID() 返回并尝试在代码中的其他位置访问惰性集合之后?在这种情况下,您要么必须getContentsbyCategoryID()
中手动加载集合(通过调用size ()
例如)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 thelist()
operation insidegetContentsbyCategoryID()
? Or is it, in fact, after you have returned fromgetContentsbyCategoryID()
and trying to access the lazy collection somewhere else in the code? In that case, you either have togetContentsbyCategoryID()
(by callingsize()
on it, for instance)