3 votes

Gestionnaire de transactions de Spring : Rollback ne fonctionne pas

Je souhaite exécuter quelques requêtes d'insertion dans un bloc de transaction où, en cas d'erreur, toutes les insertions seront annulées.

J'utilise MySQL et Gestionnaire de transactions de Spring pour ça. Le type de table est également InnoDB

J'ai effectué ma configuration en suivant les étapes mentionnées. aquí .

Voici mon code (pour l'instant une seule requête)

TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = null;

status = transactionManager.getTransaction(def);
jdbcTemplate.execute(sqlInsertQuery);
transactionManager.rollback(status);

Spring config xml :

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource">
        <ref bean="dataSource" />
    </property>
</bean>

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

Configuration de la source de données :

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="initialSize" value="${jdbc.initialSize}" />
    <property name="maxActive" value="${jdbc.maxActive}" />
    <property name="minIdle" value="${jdbc.minIdle}" />
    <property name="maxIdle" value="${jdbc.maxIdle}" />
    <property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
    <property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
    <property name="testOnReturn" value="${jdbc.testOnReturn}" />
    <property name="validationQuery" value="${jdbc.validationQuery}" />
    <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" />
    <!--<property name="removeAbandoned" value="true"/> <property name="removeAbandonedTimeout" 
        value="10"/> <property name="logAbandoned" value="false"/> -->
    <property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}" />
</bean>

Ce code fonctionne parfaitement bien et l'enregistrement est inséré. Mais le rollback ne fonctionne pas ! Il exécute l'instruction de retour en arrière sans erreur mais sans effet.

Quelqu'un peut-il m'indiquer où je me trompe ?

4voto

fpmoles Points 1181

Il semble que le problème soit que votre source de données n'est pas configurée pour avoir l'autocommit désactivé.

<property name="defaultAutoCommit" value="false"/>

Essayez ça. Je n'ai jamais utilisé le TransactionManager en dehors d'un proxy, donc je ne suis pas sûr qu'il y ait d'autres problèmes en l'utilisant directement comme cela, mais je vous recommande de regarder soit les transactions AOP, soit l'annotation de proxy AOP @Transactional, juste parce que c'est plus commun.

1voto

DarkKnightFan Points 505

EDITAR:

J'ai finalement réussi à résoudre ce problème en procédant comme suit :

dmlDataSource.setDefaultAutoCommit(false); //set autocommit to false explicitly.
Exception ex = (Exception)transactionTemplate.execute(new TransactionCallback() {
                public Object doInTransaction(TransactionStatus ts) {
                    try {
                        dmlJdbcTemplate.execute(sqlInsertQuery);
                        ts.setRollbackOnly();
                        dmlDataSource.setDefaultAutoCommit(true); // set autocommit back to true    
                        return null;
                    } catch (Exception e) {
                        ts.setRollbackOnly();
                        LOGGER.error(e);
                        dmlDataSource.setDefaultAutoCommit(true); // set autocommit back to true    
                        return e;
                    }
                }
            });

Je n'utilise pas le gestionnaire de transactions maintenant. J'utilise le trasactionTemplate et je fais ce qui suit :

Exception ex = (Exception)transactionTemplate.execute(new TransactionCallback() {
                public Object doInTransaction(TransactionStatus ts) {
                    try {
                        dmlJdbcTemplate.execute(sqlInsertQuery);
                        ts.setRollbackOnly();                           
                        return null;
                    } catch (Exception e) {
                        ts.setRollbackOnly();
                        LOGGER.error(e);
                        return e;
                    }
                }
            });

Après avoir utilisé la réponse de @Moles-JWS, je suis maintenant capable de faire un retour en arrière avec succès. Mais je veux gérer cela uniquement dans cette méthode et ne pas modifier la configuration globale de la source de données.

Puis-je le faire ici de manière programmatique ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X