Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring, hibernate and declarative transaction implementation: there is no active transaction

i try to make declarative transaction work.

This is my spring.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation=
       "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:h2:tcp://my/db/path" />
        <property name="username" value="username" />
        <property name="password" value="password" />
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="data" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
                <prop key="hibernate.current_session_context_class">thread</prop>
                <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <context:component-scan base-package="test" />

    <tx:annotation-driven/>

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

</beans>

And this is my controller implementation:

//file TestController.java
public interface TestController {

    public List<Test> findAll();

}

//file TestControllerImp.java
@Controller
public class TestControllerImp implements TestController{

    @Autowired
    private SessionFactory sessionFactory;

    /**
     * @return the sessionFactory
     */
    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    /**
     * @param sessionFactory the sessionFactory to set
     */
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory=sessionFactory;
    }

    @Transactional
    public List<Test> findAll() {
        return sessionFactory.getCurrentSession().createQuery("from Test").list();
    }

}

Both are inside package called test.

This is my try:

TestController tc=context.getBean(TestController.class);
List<Test> list=tc.findAll();

But this throw an exception:

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

Why transactionManager doesn't work? I hope with @Transactional annotation all transactions will be managed by spring framework. What can i do?

Thanks all.

like image 694
blow Avatar asked Nov 09 '10 21:11

blow


2 Answers

Remove the following lines, they are not needed when transactions are managed by Spring:

<prop key="hibernate.current_session_context_class">thread</prop> 
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop> 

Actually, setting hibernate.current_session_context_class effectively disables Spring transaction management, see AbstractSessionFactoryBean.setExposeTransactionAwareSessionFactory() javadoc:

Turn this flag off to expose the plain Hibernate SessionFactory with Hibernate's default getCurrentSession() behavior, supporting plain JTA synchronization only. Alternatively, simply override the corresponding Hibernate property "hibernate.current_session_context_class".

like image 82
axtavt Avatar answered Oct 21 '22 10:10

axtavt


I seem to recall that you can get odd behavior with stereotype-annotated classes like your @Controller, when the class implements an interface like this.

I'm not 100% sure what the workaround for this, but try one or both of the following:

  • Move the @Transactional from TestControllerImp.findAll() to TestController.findAll()
  • Add proxy-target-class="true" to your <tx:annotation-driven/>

One or both or those should do the trick, but neither is ideal. I've seen this before in other questions, and never quite got to the bottom of what's causing it.

like image 43
skaffman Avatar answered Oct 21 '22 10:10

skaffman