首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring Boot在异常时不回滚事务

Spring Boot在异常时不回滚事务
EN

Stack Overflow用户
提问于 2021-11-10 18:25:34
回答 1查看 72关注 0票数 2

我有一个简单的代码,它将一些内容保存到DB中,然后抛出一个异常,看看这些更改是否会回滚。

ResourceA.java

代码语言:javascript
复制
@Autowire ServiceA serviceA;

@PUT
@Path("/{Id:[0-9]+}")
public ObjectA updateSomethingResource(..) {
   return serviceA.upateSomethingService(..);
}

ServiceA.java

代码语言:javascript
复制
@Transactional(rollbackFor=Exception.class)
public ObjectA upateSomethingService(EntitlementRequest entitlementRequest) throws ServiceException {

    ObjectA objectA = getObjectFromDB(..);
    objectA.setName("New Name");
    dao.save(objectA)
    throw new ServiceException("error"); //ServiceException extends Exception
}

在执行此操作时,我检查了DB,对象的名称仍然是New Name。我会期望它回滚到它最初的样子。

为了理解发生了什么,我试着看看我可以启用什么日志,我唯一成功启用的是logging.level.org.springframework.transaction.interceptor=TRACE

这就给出了:

代码语言:javascript
复制
TRACE o.s.t.i.TransactionInterceptor - Getting transaction for [xxxxx.upateSomethingService] 
TRACE o.s.t.i.TransactionInterceptor - Completing transaction for [xxxxx.upateSomethingService] after exception: xxx.ServiceException 

因此,事务管理器确实看到了异常,但没有任何内容被回滚。

是否需要在某个地方启用某些功能才能使回滚真正工作?我还可以启用哪些日志来准确地显示正在发生的情况?

更新:我已经设法用logging.level.org.springframework=DEBUG展示了ore日志

代码语言:javascript
复制
DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 
DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 
DEBUG o.s.j.s.JdbcTransactionManager - Creating new transaction with name [xxx.service.upateSomethingService]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception 
DEBUG o.s.j.s.JdbcTransactionManager - Acquired Connection [1091371323, URL=jdbc:mysql://localhost:3306/table?allowMultiQueries=true, UserName=root@localhost, MySQL Connector/J] for JDBC transaction 
DEBUG o.s.j.s.JdbcTransactionManager - Switching JDBC Connection [1091371323, URL=jdbc:mysql://localhost:3306/table?allowMultiQueries=true, UserName=root@localhost, MySQL Connector/J] to manual commit 
DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 
DEBUG o.s.j.s.JdbcTransactionManager - Initiating transaction rollback 
DEBUG o.s.j.s.JdbcTransactionManager - Rolling back JDBC transaction on Connection [1091371323, URL=jdbc:mysql://localhost:3306/table?allowMultiQueries=true, UserName=root@localhost, MySQL Connector/J] 
DEBUG o.s.j.s.JdbcTransactionManager - Releasing JDBC Connection [1091371323, URL=jdbc:mysql://localhost:3306/table?allowMultiQueries=true, UserName=root@localhost, MySQL Connector/J] after transaction 

看看这些日志..spring实际上告诉我它“正在”回滚事务..但在数据库中什么都不会改变?

奇怪的是,我刚刚注意到的是,在dao.save(objectA)之后,我已经可以在DB中看到名称正在更改。因此,不知何故,MyBatis是自动提交的,并且看起来它使用的连接与我在日志中看到的连接不同

这就是我设置数据库源和配置MyBatis的方法

(我有两个数据源,这就是为什么我使用它,而不是仅仅使用application.properties属性。)

代码语言:javascript
复制
@Bean(name = MYBATIS_DATASOURCE_ONE, destroyMethod = "")
  public DataSource dataSource(....) throws SQLException {

    PooledDataSource dataSource = new PooledDataSource();
    dataSource.setDriver(driverclassname);
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);
    [...]
    return dataSource;
  }

@Bean(name = A_SESSION_FACTORY, destroyMethod = "")
  @Primary
  public SqlSessionFactory sqlSessionFactory(@Qualifier(MYBATIS_DATASOURCE_A) DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/mapper/*.xml"));
    final SqlSessionFactory sqlSessionFactory = factoryBean.getObject();
    return sqlSessionFactory;
  }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-10 21:08:30

你的最新更新让它变得更加清晰...我认为发生的情况是,Spring在实例化DataSourceTransactionManager时没有使用您手动定义的DataSource。它可能正在使用BasicDataSource或类似的东西(使用application.properties中的属性创建的your

MyBatis documentation clearly specifies that for Transaction to work the DataSourceTransactionManager needs to have the exact same Datasource the rest of your app is using otherwise it won't work.

将它添加到您的配置中,事务就应该开始工作了

代码语言:javascript
复制
@Bean
public DataSourceTransactionManager transactionManager(@Qualifier(MYBATIS_DATASOURCE_A) DataSource dataSource) {
  DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
  transactionManager.setDataSource(dataSource);
  return transactionManager;
}

通常,您不需要手动定义此Bean,因为Spring会自动为您定义。但由于您使用的是自己的DataSource,因此需要这样做。

如果你想验证这一点。不要声明此bean并在DataSourceTransactionManager构造函数中放置断点。您应该注意到,DataSource与您自己声明的实例不是同一个实例。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69918403

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档