简体   繁体   中英

Spring Data, Hibernate, Transactions and rolling back on exceptions

I have two repositories:

  • locationRepository
  • playerRepository

Consider the following situation:

@Transactional
public Player createPlayer(String locationName, String name) {
    Location location = new Location(locationName);
    location = locationRepository.save(location);

    Player player = new Player(name, location);
    return playerRepository.save(player);
}

There is constraint violation on player entity. I get: org.springframework.dao.DataIntegrityViolationException

After that, I check the database:

  • player was not created
  • location was created

This method is annotated with @Transaction. So why the location is not rolled back? I was expecting that neither of this two were saved to DB on exception. How to rollback also the location?

EDIT:

@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(JpaVendorAdapter adapter) {
    ...

    LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactory.setDataSource(dataSource);
    entityManagerFactory.setJpaVendorAdapter(adapter);
    entityManagerFactory.setPackagesToScan(packagesToScan);
    entityManagerFactory.setJpaProperties(properties);

    return entityManagerFactory;
}

@Bean
PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) 
{
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}

@Bean
PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
    return new PersistenceAnnotationBeanPostProcessor();
}

@Bean
JpaVendorAdapter createVendorAdapter() {
    HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    adapter.setDatabase(Database.MYSQL);
    adapter.setDatabasePlatform(MySQL5Dialect.class.getName());

    return adapter;
}

EDIT:

Interesting thing is that the entry is persisted to database just after this call:

location = locationRepository.save(location);

I've set a breakpoint just after this call and checked the database. The entry was inserted immediately.

@Transactional should work in case of Spring based transaction management if your spring configuration is properly setup. If it is still not working then you can programmatically rollback a transaction in catch block by adding following line of code-

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Also, what the import you are using for @Transactional, make sure it is -

import org.springframework.transaction.annotation.Transactional

The problem was with MySQL. I didn't know that MyISAM doesn't support transactions.

The MySQL5InnoDBDialect is needed in order for transactions to rollback the database. This changed the engine from engine=MyISAM to engine=InnoDB . InnoDB Table Schemas support transactions.

I modified my spring boot 2.0 application.properties file and added the following:

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

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