`

saveOrUpdate is not valid without active transaction

 
阅读更多

在使用Spring+Hibernate的框架时,在applicationContext.xml中配置了如下的代码片段:

 

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="dataSource">

<ref local="dataSource"/>

</property>

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">${hibernate.dialect}</prop>

<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>

<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>

<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>

<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>

<!-- 绑定会话到当前线程 -->

<prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop> 

</props>

</property>

<property name="mappingLocations">

<list>

<value>classpath:/com/changetech/model/*.hbm.xml</value>

</list>

</property>

</bean>


在调用Dao(是使用声明式事务管理@Transactional注解来进行配置的)层时,

 

@Transactional

public void saveOrUpdate(T t)

{

getSession().saveOrUpdate(t);

}

 

出现以下的错误:

 

org.hibernate.HibernateException: saveOrUpdate is not valid without active transaction

at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:338)

at $Proxy23.saveOrUpdate(Unknown Source)

at com.changetech.dao.impl.BaseDao.saveOrUpdate(BaseDao.java:49)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)

at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)

at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)

at $Proxy15.saveOrUpdate(Unknown Source)

at com.changetech.service.impl.BaseService.saveOrUpdate(BaseService.java:22)

at com.changetech.client.MultiThreadServiceTest.sampleTest(MultiThreadServiceTest.java:51)

at com.changetech.client.MultiThreadServiceTest$ThreadB.runTest(MultiThreadServiceTest.java:66)

at net.sourceforge.groboutils.junit.v1.TestRunnable.run(TestRunnable.java:154)

at java.lang.Thread.run(Thread.java:619)

 

经过在网上查找原因,说是Hibernate源码里做了一些修改,说是,hibernate里的所有操作(包括get\load\delete\list\saveOrUpdate等)都必须在transcation.isActive()条件下才可以执行,否则就会出现上述的错误。

 

<prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop> 

如果把这句话去掉之后(Hibernate就开始利用Spring的事务管理),此错误就消失,目前还不知道是为什么。

但是对于spring如何默认打开Transaction还不是很清楚。

 

外部连接:

 

If you use spring 2.5 as a drop in replacement @Transactional isn't working any more.
They HibernateSession you get through a currentSession() has no active transaction and result in the following stack trace

Exception in thread "main" org.hibernate.HibernateException: createSQLQuery is not valid without active transaction
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:297)
at $Proxy7.createSQLQuery(Unknown Source)
at ag.pinguin.myservice.impl.MyService.doSomething(MyService.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:301)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy5.doSomething(Unknown Source)
at test.SpringTestMain.main(SpringTestMain.java:16)

With spring 2.0.7 the exact same code/config works fine

As of Spring 2.5, Spring uses a custom CurrentSessionContext implementation plugged into Hibernate (requires Hibernate 3.1+). Previously, Spring created a special SessionFactory proxy (which also worked with Hibernate 3.0.)

 

Note that your hibernate.cfg.xml specifies

<property name="current_session_context_class">thread</property>

This overrides the default CurrentSessionContext (Spring's) with the standard Hibernate thread-local context. This leads to the failure that you see. Spring 2.5 simply respects your configuration there – in this case, wrong configuration that Spring 2.0 simply ignored. In any case: You shouldn't have specified that even when using Spring 2.0!


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics