【问题标题】:Spring-boot with MyBatis doesn't rollback transactions使用 MyBatis 的 Spring-boot 不会回滚事务
【发布时间】:2020-02-06 16:32:45
【问题描述】:

我有一个 Spring Boot(版本 2.1.8.RELEASE)Web 应用程序(部署在 Wildfly 9 应用程序容器中),使用 Spring Boot 启动器自动配置 MyBatis,但使用 @transactional注释,语句总是被提交,即使它们应该被回滚。我的 pom.xml 片段如下所示:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

我的 application.properties 中有以下几行:

spring.datasource.url=jdbc:sqlserver://my.server.com:1433;databaseName=MyDatabase
spring.datasource.username=myUsername
spring.datasource.password=myPassword
mybatis.config-location=classpath:mybatis-config.xml

这是我的 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="localCacheScope" value="STATEMENT"/>
    </settings>
    <typeAliases>
        <package name="my.package.model"/>
    </typeAliases>
    <mappers>
    ...
    </mappers>
</configuration>

我的应用初始化程序类如下所示:

@SpringBootApplication
@EnableTransactionManagement
@ComponentScan("my.packag e")
public class ServletInitializer extends SpringBootServletInitializer
{
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) 
    {
        // some config here

        return builder.sources(ServletInitializer.class);
    } // end method configure()

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException
    {
        super.onStartup(servletContext);
        // some config here
    } // end method onStartup()

    // some other beans here

    public static void main(String[] args) 
    {
        SpringApplication.run(ServletInitializer.class, args);
    }

} // end class ServletInitializer

我有一个控制器,它不是事务的一部分,而是在服务层 bean 中自动装配:

@Controller
public class DataMigrationController
{

    @AutoWired private MyService service;

    @GetMapping("/path")
    public @ResponseBody Boolean something(Model model, HttpSession session)
    {
        service.doTask();
        return true;
    }
}

而我的服务类是这样的:

@Service
public class MyService
{

    @AutoWired private MyMapper mapper;

    @Transactional(rollbackFor=Throwable.class) 
    public void doTask()
    {
        Person p= new Person();
        p.setPersonID("999999");
        p.setSurname("TEST");
        p.setForename1("TEST");
        p.setTitle("Mr");

        mapper.insertPerson(p);
        throw new RuntimeException();
    }
}

我希望事务能够回滚,因为 RuntimeExceptiondoTask() 方法的末尾被抛出,但是当我检查数据库时,该行存在。我也尝试过使用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 而不是抛出异常,但我得到了相同的结果。

我正在使用this blog post 建议的事务调试类,它告诉我控制器中没有事务(我希望如此)并且服务类中有一个。但由于某种原因,事务并没有回滚。

谁能给点建议?

【问题讨论】:

  • 您使用的是哪个数据库?
  • 这是 SQL Server 2017。
  • @Raj 您使用的 jdbc 驱动程序版本是什么?您是否尝试过事务性(无需声明回滚)。
  • @Ian 版本是 7.2.2.jre8(使用 Maven 获取,artifactId mssql-jdbc),是的,我尝试不使用 rollbackFor 参数并得到相同的结果。
  • 您是否声明了 DataSourceTransactionManager bean?

标签: spring-boot transactions mybatis spring-mybatis


【解决方案1】:

我找到了提交事务的原因。 Spring Boot默认使用Java EE(Jakarta EE)环境下的JTA事务管理。但是通过Spring Boot创建的DataSource不能加入。

您可以选择如下解决方案:

  • 禁用 JTA 事务管理
  • 使用由 Wildfly 管理的事务性DataSource

如何禁用 JTA 事务管理

您可以按如下方式禁用 JTA 事务管理:

spring.jta.enabled=false

详情请见https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/htmlsingle/#boot-features-jta

如何使用 Wildfly 管理的DataSource

您可以使用 Wildfly 管理的DataSource

spring.datasource.jndi-name=java:jboss/datasources/demo

详情见https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/htmlsingle/#boot-features-connecting-to-a-jndi-datasource

注意:如何在 Wildfly 上配置 DataSource(需要启用 JTA),请参阅 https://docs.jboss.org/author/display/WFLY9/DataSource+configuration?_sscc=t

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-27
    • 2020-03-11
    • 1970-01-01
    • 2018-11-05
    • 2019-03-30
    • 2016-09-15
    • 2016-10-07
    • 2017-11-07
    相关资源
    最近更新 更多