0

My @Transactional annotation doesn't rollback the first insert when the second update sentence fails (with a non-RuntimeException). The exception is launched in updateNumeroVotos but Spring doesn't rollback the insert of save operation. Any idea?

I have these files:

IdeaService.java code:

@Service
public class IdeasServiceImpl implements IdeasService {

@Autowired
all daos code

/**
 * Metodo que inserta un voto de un usuario
 */
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void incorporarVoto(String token, Integer id) throws Exception {
    IdeaVotoVO ideaVoto = new IdeaVotoVO();

    ideaVoto.setUsuario(usuariosService.getDatosTokenUsuario(token).getLoginCiudadano());
    ideaVoto.setIdIdea(id);
    ideaVoto.setVoto(ConstantesModel.IDEA_VOTO_POSITIVO);

    if (validarVoto(ideaVoto)) {
        ideaVotoDAO.save(ideaVoto);         
        ideaDatosDao.updateNumeroVotos(new Timestamp(Generic.getFechaActual()), id);
    }

}

applicationContext.xml

<mvc:annotation-driven />
<mvc:default-servlet-handler />

<context:component-scan base-package="example.code.xxxx.*" />

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">

    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="jdbc:oracle:thin:@ora11g:1521:xxxxxx" />
    <property name="username" value="xxxxxx" />
    <property name="password" value="yyyyy" />
    <property name="validationQuery" value="SELECT SYSDATE FROM DUAL" />
    <property name="maxIdle" value="3" />
    <property name="poolPreparedStatements" value="true" />
    <property name="maxOpenPreparedStatements" value="100" />
    <property name="maxWaitMillis" value="10000" />
    <property name="maxTotal" value="20" />
</bean>

<bean id="sessionFactoryCiud"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">validate</prop>
        </props>
    </property>
    <property name="mappingResources">
        <list>
            <<--Here de entity's-->
        </list>
    </property>
</bean>



<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="ehcache" />
</bean>

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
    p:config-location="classpath:ehcache.xml" />


<bean id="TransactionManagerCiud"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactoryCiud" />
    <qualifier value="ciudada" />
</bean>


<tx:annotation-driven transaction-manager="TransactionManagerCiud" proxy-target-class="true"/>



<bean id="ideasService"
    class="example.code.xxxx.service.ideas.impl.IdeasServiceImpl">
</bean>



<bean id="IdeaVotoDAO"
    class="example.code.xxxx.model.ideas.impl.IdeaVotoDAOImpl">
    <property name="sessionFactory" ref="sessionFactoryCiudadania" />
</bean>

<bean id="IdeaDatosDAO"
    class="example.code.xxxx.model.ideas.impl.IdeaDatosDAOImpl">
    <property name="sessionFactory" ref="sessionFactoryCiud" />
</bean>
</beans>

I tried to add this lines but it dont work

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="*" rollback-for="Exception"/>
    </tx:attributes>
</tx:advice>
MickeyBG
  • 25
  • 1
  • 2
  • 11
  • Has `ideaVotoDAO`any `@Transactional` annotations? – xerx593 Apr 29 '15 at 21:49
  • No, they dont have ¿Is it needed? – MickeyBG Apr 29 '15 at 21:56
  • By default Spring rolls back only `RuntimeException`s. (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-rolling-back) What kind of `Exception` does your method throw? It might be also the cause of not enabling `@EnableTransactionManagement` in the configuration (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#tx-decl-explained). – Gábor Bakos Apr 29 '15 at 21:56
  • I need to rollback all kind of transactions not only the runtime exception. ¿Is any way to declare it on application context? – MickeyBG Apr 29 '15 at 22:04
  • please try to place log4j.logger.org.springframework.transaction.interceptor = trace in your log4j.properties !!! – Dev Apr 30 '15 at 04:15

3 Answers3

3

Then, please add:

rollbackFor = Exception.class

to your @Transactional annotation.


EDIT:

If you don't want to edit each of your @Transactional annotatinos, please look at this interesting approach.

From the start a good design would be, if (all of) your services would throw (a customized type of) RuntimeException, when something rollbackable happens. (But this seems more complex than modifying all annotations.)

Community
  • 1
  • 1
xerx593
  • 12,237
  • 5
  • 33
  • 64
  • Yes i tried this and it works but is a "general way" to do this for all @transational methods and dont write that anottation? – MickeyBG Apr 29 '15 at 22:08
  • Thank you. It's a really big surprise for me to find out that this is not default behavior. – Marboni Jun 29 '15 at 09:17
1

You can provide tx:advices for the transaction managers like this:

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="*" rollback-for="Exception"/>
    </tx:attributes>
</tx:advice>

(as explained in the documentation.)

Gábor Bakos
  • 8,982
  • 52
  • 35
  • 52
0

What is "sessionFactoryCiudadania" used by "ideaVotoDao" and why is it different from the SessionFactory used by your transaction manager? The annotation is only going to rollback content from the session that it created.... If a DAO is using a different session internally it's going to commit based on its own rules (which probably means basic autoCommit mode.)

Affe
  • 47,174
  • 11
  • 83
  • 83