Impossible de rollbacker une transaction JDBC !
Bonjour,
j'ai un service de création d'utilisateurs, dont je me sert pour tester la gestion des transactions avec Spring et JDBC en utilisant un TransactionTemplate. Pourtant, si je déclenche une exception en créant 2 fois le même utilisateur, et que je mets le status de la transaction à rollbackOnly, les utilisateurs créés précédemment dans la même transaction sont toujours là !
Voici un extrait du code de mon service :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
private TransactionTemplate txTemplate;
private IUserDao userDao;
public UserService(IUserDao dao, PlatformTransactionManager txManager) {
this.userDao = dao;
txTemplate = new TransactionTemplate(txManager);
}
public User testTransaction( ) {
txTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
User user = null;
user = txTemplate.execute(new TransactionCallback<User>( ) {
@Override
public User doInTransaction(TransactionStatus status) {
User user = null;
try {
createUser("étienne", "789456");
createUser("marcel", "123456");
user = createUser("étienne", "789456");
} catch (DataAccessException e) {
status.setRollbackOnly( );
if ( !status.isNewTransaction( ))
throw e;
}
return user;
}
});
return user;
}
public User createUser(final String login, final String password) {
txTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
return txTemplate.execute(new TransactionCallback<User>( ) {
@Override
public User doInTransaction(TransactionStatus status) {
String hashPassword = BCrypt.hashpw(password, BCrypt.gensalt( ));
User user = null;
try {
userDao.createUser(login, hashPassword);
} catch (DataAccessException e) {
status.setRollbackOnly( );
if ( !status.isNewTransaction( ))
throw e;
}
return user;
}
});
} |
Un extrait de UserDao :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
private NamedParameterJdbcTemplate template;
public void setDatasource(DataSource datasource) {
template = new NamedParameterJdbcTemplate(datasource);
}
public User createUser(String login, String hashPassword) {
MapSqlParameterSource params = new MapSqlParameterSource( );
params.addValue("login", login);
params.addValue("hashPassword", hashPassword);
template.update(createUserQuery, params);
return new User(login, hashPassword);
} |
Voici mon fichier de configuration pour l'injection des beans :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="xx"/>
<property name="password" value="yy"/>
<property name="url" value="jdbc:mysql://localhost/gesicoba"/>
<property name="defaultAutoCommit" value="false"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<bean id="userDao" class="fr.atatorus.gesicoba.dao.UserDao" init-method="init">
<property name="datasource" ref="datasource"/>
<property name="queryLoader" ref="queryLoader"/>
</bean>
<bean id="userService" class="fr.atatorus.gesicoba.services.UserService">
<constructor-arg ref="userDao"/>
<constructor-arg ref="txManager"/>
</bean> |
Et enfin le code de mon test unitaire :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( {
"../test-application-context.xml"
})
public class UserServiceTest {
@Resource
private IUserService userService;
@Test
public void testTransaction( ) {
User user = userService.testTransaction( );
assertNull(user);
user = userService.connectUser("étienne", "789456");
assertNull(user);
}
....
} |
Puisque je crée 2 fois étienne, j'obtiens bien une exception, dans laquelle je mets bien le status de la transaction à rollbackOnly. Pourtant quand je regarde dans ma base, étienne existe bien, le rollback n'a pas eu lieu...
Un grand merci à ceux qui me donneront la source du mystère !!
Edit : j'ai fini par trouver. Le problème ne venait pas de mon code, mais de mySql. Je n'avais pas précisé à la création le moteur à utiliser, et ma table était de type MyIsam. En indiquant que je voulais un moteur InnoDB, ça fonctionne.