简体   繁体   中英

Spring 3 problems with TransactionManager and annotations

I'm trying to setup a TransactionManager in my Web Application (powered by Spring MVC 3), as I need to have one method of a component annotated as @Transactional .

This is my situation:

  • web.xml : load 2 xml files for the Spring ContextLoaderListener ( applicationContext.xml and database.xml )
  • applicationContext.xml: contains some beans which I can't define via annotation, plus the tags for annotation, plus the usual context:annotation-config and context:component-scan (this component-scan includes the package that contains the @Transactional method)
  • database.xml : contains the datasource (I'm using BasicDataSource from commons-dbcp), the transaction manager definition and tx:annotation-driven.

I've got a @Component (DeleteComponent ) which has an interface and an implementation ( DeleteComponentImpl ). The implementation class is annotated with @Component and has one public method annotated with @Transactional (I annotated the concrete class and not the interface, as Spring documentation states). For @Transactional I didn't put any arguments, as defaults are fine. This class has some DAOs (annotated with @Repository ) being injected via @Autowired . I'm using only plain JDBC (no Hibernate or other ORM). This @Component is injected into a @Controller (which is defined in spring- servlet.xml ).

If the method annotated as @Transactional throws an exception (unchecked, as RuntimeException ), however, nothing is rolled back. The database retains the changes did before the exception. I'm using Jetty web server for testing locally my application. The thing I noticed is actually that seems like no transaction manager is being set up. Actually, my transaction manager is named transactionManager . The xml line to set up the annotation-driven transaction is

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

If I change it to use a non-existing bean name like

<tx:annotation-driven transaction-manager="fake"/>

The application still deploys correctly and doesn't complain.

Any tips on what should I check to make it working?

Thanks.

I solved by using @Transactional(rollbackFor = RuntimeException.class) and switching from a BasicDataSource to a ComboPooled that's present in c3p0 library. Thanks for the suggestions though.

To get rollback when an exception is thrown add this:

@Transactional(rollbackFor=Exception.class)

You will also need to set up the transactionManger bean (here is mine, using hibernate):

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" 
                p:sessionFactory-ref="sessionFactory" />

I found thistutorial informative.

I believe that @Autowired and @Resource aren't scanned by Spring on a @Component . Try to use a ContextHolder class to get the context and the DAO

@Component
public class ContextHolder implements ApplicationContextAware {

    /** 
     * Spring context which will directly be injected by Spring itself
     */
    private static ApplicationContext context = null;

    /**
     * Overridden method of ApplicationContextAware, which will automatically be called by the container
     */
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }

    /**

    /**
     * Static method used to get the context
     */
    public static ApplicationContext getApplicationContext() {
        return context;
    }
}

and call your dao with:

ContextHolder.getApplicationContext().getBean("MyDAO");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM