8

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.

2 Answers 2

20

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".

Sign up to request clarification or add additional context in comments.

3 Comments

Bingo! Thank you! My goal is to make extensive use of annotations(@Autowired, @Transactional ecc) in order to reduce the amount of config to write into xml file. Im going in the right direction? I have to change something or do some optimization?
@blow: Yes, you are going in right direction. Note that if you use Spring 3 and really dislike XML configs, you may reduce number of infrastructure components (such as transactionManager, sessionFactory, etc) in XML by configuring them using @Configuration.
Is there any documentation which says about removing the above keys to enable Spring manage the transaction ?
1

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.

1 Comment

thank you for reply, i try both, <tx:annotation-driven proxy-target-class="true"/> and move @Transactional at interface level, but the problem still remains.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.