我正在使用Hibernate和OpenSessionInViewInterceptor,因此单个Hibernate会话将用于整个HTTP请求(或者我希望如此)。问题是Spring配置的事务边界导致创建一个新会话,所以我遇到了以下问题(伪代码):
配置如下:
<bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor" autowire="byName">
<property name="flushModeName">
<value>FLUSH_AUTO</value>
</property>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="useTransactionAwareDataSource" value="true" />
<property name="mappingLocations">
<list>
<value>/WEB-INF/xml/hibernate/content.hbm.xml</value>
</list>
</property>
<property name="lobHandler">
<ref local="oracleLobHandler" />
</property>
<!--property name="entityInterceptor" ref="auditLogInterceptor" /-->
<property name="hibernateProperties"
ref="HibernateProperties" />
<property name="dataSource" ref="myDataSource" />
</bean>
我做了一些调试,并确切地知道这发生了什么,这里是堆栈跟踪:
Daemon Thread [http-8080-1] (Suspended (entry into method doUnbindResource in TransactionSynchronizationManager))
TransactionSynchronizationManager.doUnbindResource(Object) line: 222
TransactionSynchronizationManager.unbindResource(Object) line: 200
SpringSessionSynchronization.suspend() line: 115
DataSourceTransactionManager(AbstractPlatformTransactionManager).doSuspendSynchronization() line: 620
DataSourceTransactionManager(AbstractPlatformTransactionManager).suspend(Object) line: 549
DataSourceTransactionManager(AbstractPlatformTransactionManager).getTransaction(TransactionDefinition) line: 372
TransactionInterceptor(TransactionAspectSupport).createTransactionIfNecessary(TransactionAttribute, String) line: 263
TransactionInterceptor.invoke(MethodInvocation) line: 101
ReflectiveMethodInvocation.proceed() line: 171
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 204
$Proxy14.changeVisibility(Long, ContentStatusVO, ContentAuditData) line: not available
我无法弄清楚为什么事务边界(甚至是“嵌套”的 - 虽然在这里我们只是从SUPPORTS转移到REQUIRED)会导致Hibernate会话被挂起,即使OpenSessionInViewInterceptor正在使用中。
当会话未绑定时,我会在日志中看到以下内容:
[2010-02-16 18:20:59,150] DEBUG org.springframework.transaction.support.TransactionSynchronizationManager Removed value [org.springframework.orm.hibernate3.SessionHolder@7def534e] for key [org.hibernate.impl.SessionFactoryImpl@693f23a2] from thread [http-8080-1]
答案 0 :(得分:2)
首先,您的openSessionInViewInterceptor
必须注明sessionFactory
,否则无法完成任务:
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
此外,还有一个名为singleSession
的属性 - 默认情况下为true
,但调整其值以防万一。
然后,如果使用Spring-MVC,则必须为SimpleUrlHandlerMapping
(或者您使用的任何一个)配置拦截器,以便可以实际应用它:
<property name="interceptors">
<list>
<ref bean="openSessionInViewInterceptor"/>
</list>
</property>
如果使用其他任何内容,我认为您必须使用<aop>
标记来定义它(您使用的是哪种Web框架?)
答案 1 :(得分:0)
我有同样的问题。我首先想到数据库事务边界驱动了hibernate会话的创建。经过一些调试后,我意识到我并不真正了解它们 - 或者它们应该如何“设置”。
我正在使用spring和一个带有两个相关DAO的@Transactional服务。我也在全面使用默认传播(REQUIRED)。
public class MyService {
public MyPersonDao personDao; // injected by spring
public MyAddressDao addressDao; // injected by spring
@Transactional
public void create(Person p) {
Address a = addressDao.findOrCreate(p.getAddressData());
boolean inSession = personDao.getHibernateTemplate.contains(a); // false
p.setAddress(adressDao.create();
personDao.store(p); // fails because a is transient
}
}
从我在日志中看到的,看起来通过事务代理的函数调用似乎打开和关闭了hibernate会话。