【问题标题】:Spring Boot @Transaction not rolling back on RuntimeExceptionSpring Boot @Transaction 不会在 RuntimeException 上回滚
【发布时间】:2025-11-30 12:25:01
【问题描述】:

我有一个使用 spring-boot-starter-jdbc、Java 8 和 MySQL 和 InnoD 的 Spring Boot 应用程序。即使我这样做,应用程序也不会回滚运行时异常:

throw new RuntimeException("Rolling back");

我正在像这样配置我的交易:

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

我正在使用 Spring Boot Actuator,我可以在 Hal 浏览器中看到这个:

"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"
  }
],

我假设这意味着事务管理器已成功配置,所以我不确定为什么事务没有回滚。是

有什么想法吗?

DAO 接口:

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 实现:

@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

【问题讨论】:

  • 向我们展示了一个代码示例
  • 你能添加你的application.properties吗?
  • 在你的@SpringBootConfiguration 类中......你有一些关于实体管理器/事务管理器的额外配置吗?
  • 您使用的是 JDK 还是 CGLIB 哪个代理?在 CGLIB 的情况下,这将不起作用,因为接口注释没有被继承。
  • Maciej,我没有关于实体管理器或事务管理器的额外配置

标签: spring spring-boot transactions spring-jdbc


【解决方案1】:

您的@Transactional 注释位于接口上(可以说这是一个坏主意,为什么您希望此类特定于实现的细节出现在您的合同中?)。 Spring Boot 默认使用 CGLIB 代理,因此据我所知,您根本没有任何事务。

您可以在@SpringBootApplication 上添加@EnableTransactionManagement(proxyTargetClass=false) 以确认这是问题的根本原因。

【讨论】:

    【解决方案2】:

    所以问题在于@Transactional 注释在接口上。将@Transactional 注释放在界面上是我更喜欢做的事情,我已经做了一段时间了,但是由于这是一个 Spring Boot 应用程序,它不起作用。感谢您为我指明正确的方向。

    【讨论】: