Spring-使用 MyBatis 启动不会回滚事务
Spring-boot with MyBatis doesn't rollback transactions
我有一个 Spring Boot(版本 2.1.8.RELEASE)Web 应用程序(部署在 Wildfly 9 应用程序容器内),带有 MyBatis,使用 Spring Boot starter,但是当使用 @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>
我的应用程序初始化程序 class 如下所示:
@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;
}
}
而我的服务class是这样的:
@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();
}
}
由于 RuntimeException
在 doTask()
方法的末尾抛出,我希望事务回滚,但是当我检查数据库时,该行存在。我也试过使用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
而不是抛出异常,但我得到了相同的结果。
我正在使用 this blog post 建议的事务调试 class,它告诉我控制器中没有事务(我希望如此)而服务中有一个 class.但是由于某种原因,事务没有回滚。
谁能指点一下?
我找到了提交交易的理由。 Spring Boot默认使用Java EE(Jakarta EE)环境下的JTA事务管理。但是通过Spring Boot创建的DataSource
无法加入
您可以select解决方法如下:
- 禁用 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
注意:如何在Wildfly上配置DataSource
(需要启用JTA),参见https://docs.jboss.org/author/display/WFLY9/DataSource+configuration?_sscc=t。
我有一个 Spring Boot(版本 2.1.8.RELEASE)Web 应用程序(部署在 Wildfly 9 应用程序容器内),带有 MyBatis,使用 Spring Boot starter,但是当使用 @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>
我的应用程序初始化程序 class 如下所示:
@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;
}
}
而我的服务class是这样的:
@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();
}
}
由于 RuntimeException
在 doTask()
方法的末尾抛出,我希望事务回滚,但是当我检查数据库时,该行存在。我也试过使用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
而不是抛出异常,但我得到了相同的结果。
我正在使用 this blog post 建议的事务调试 class,它告诉我控制器中没有事务(我希望如此)而服务中有一个 class.但是由于某种原因,事务没有回滚。
谁能指点一下?
我找到了提交交易的理由。 Spring Boot默认使用Java EE(Jakarta EE)环境下的JTA事务管理。但是通过Spring Boot创建的DataSource
无法加入
您可以select解决方法如下:
- 禁用 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
注意:如何在Wildfly上配置DataSource
(需要启用JTA),参见https://docs.jboss.org/author/display/WFLY9/DataSource+configuration?_sscc=t。