SME
SME

Reputation: 556

Spring Boot @Transaction not rolling back on RuntimeException

I have a spring boot application that is using spring-boot-starter-jdbc, Java 8 and MySQL with InnoD. The application isn't rolling back Runtime Exceptions, even when I do this:

throw new RuntimeException("Rolling back");

I am configuring my Transactions like this:

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)    

I am using the Spring Boot Actuator and I can see this in the Hal Browser:

"DataSourceTransactionManagerAutoConfiguration": [
  {
    "condition": "OnClassCondition",
    "message": "@ConditionalOnClass found required classes 'org.springframework.jdbc.core.JdbcTemplate', 'org.springframework.transaction.PlatformTransactionManager'"
  }
],
"DataSourceTransactionManagerAutoConfiguration.DataSourceTransactionManagerConfiguration": [
  {
    "condition": "OnBeanCondition",
    "message": "@ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) found a primary bean from beans 'psmDataSource', 'dataSource'"
  }
],
"DataSourceTransactionManagerAutoConfiguration.DataSourceTransactionManagerConfiguration#transactionManager": [
  {
    "condition": "OnBeanCondition",
    "message": "@ConditionalOnMissingBean (types: org.springframework.transaction.PlatformTransactionManager; SearchStrategy: all) did not find any beans"
  }
],
"DataSourceTransactionManagerAutoConfiguration.TransactionManagementConfiguration": [
  {
    "condition": "OnBeanCondition",
    "message": "@ConditionalOnMissingBean (types: org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration; SearchStrategy: all) did not find any beans"
  }
],

I'm assuming that this means that a Transaction Manager has been successfully configured, so I'm not sure why the transactions aren't being rolled back.Is

Any ideas?

DAO Interface:

public interface IContestService {
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)    
    ContestDTO create(final ElectionEventDTO electionEvent, final ElectionDTO election, final ContestDTO contest, final PollingPlaceDTO pollingPlace, final List<CandidateDTO> candidates);
}

DAO Implemtnation:

@Override
public ContestDTO create(final ElectionEventDTO electionEvent, final ElectionDTO election, final ContestDTO contest, final PollingPlaceDTO pollingPlace, final List<CandidateDTO> candidates) {

    if(electionEvent.getId() == null) {
        getElectionEventService().save(electionEvent);
    }

    if(election.getId() == null) {
        election.setElectionEvent(electionEvent);
        getElectionService().save(election);
    }

    if(election != null) {
        throw new RuntimeException("Rolling back");
    }
    contest.setElection(election);
    getContestDAO().save(contest);

    getCandidateService().save(candidates);

    /**
     * Return the contest
     */
    return contest;
}

application.properties:

logging.file=cm-web.log
logging.level.org.springframework.web=DEBUG

countdb.datasource.url=jdbc:mysql://localhost/countdb
countdb.datasource.username=root
countdb.datasource.password=pass123
countdb.datasource.driver-class-name=com.mysql.jdbc.Driver

psm.datasource.url=jdbc:mysql://localhost/psm
psm.datasource.username=root
psm.datasource.password=password
psm.datasource.driver-class-name=com.mysql.jdbc.Driver

Upvotes: 2

Views: 4731

Answers (2)

SME
SME

Reputation: 556

So the problem was that the @Transactional annotation was on an interface. Putting @Transactional annotations on an interface is something I prefer to do and I have done for some time, however as this was a Spring Boot app it didn't work. Thanks for pointing me in the right direction.

Upvotes: 0

Stephane Nicoll
Stephane Nicoll

Reputation: 33091

Your @Transactional annotation is on an interface (which arguably is a bad idea, why would you want such implementation-specific details to show up in your contract?). Spring Boot uses CGLIB proxy by default so you simply don't have any transaction at all as far as I can see.

You can add @EnableTransactionManagement(proxyTargetClass=false) on your @SpringBootApplication to confirm this is the root cause of the issue.

Upvotes: 1

Related Questions