问题
在测试事务传播行为的时候,使用单位测试加了@Transactional,一开始是正常,后面出现了异常,即使没有报错的情况下,事务也会自动回滚
代码
@RunWith(SpringRunner.class)
@SpringBootTest
public class TranTest {
@Autowired
private KsAService ksAService;
@Autowired
private KsBService ksBService;
@Test
@Transactional
public void test() {
KsA ksA = new KsA();
ksA.setName("林");
ksAService.insert(ksA);
KsB ksB = new KsB();
ksB.setAge(10);
ksBService.insert(ksB);
}
}
异常
2022-10-20 11:27:31.818 [TID: N/A] [main] INFO o.s.t.c.t.TransactionContext -Began transaction (1) for test context [DefaultTestContext@c430e6c testClass = TranTest, testInstance = com.forlan.kaoshi.TranTest@ce0c2b3, testMethod = test@TranTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@312aa7c testClass = TranTest, locations = '{}', classes = '{class com.forlan.kaoshi.KaoshiApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@418e7838, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@3e2e18f2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@48ae9b55, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@72f926e6, org.spockframework.spring.mock.SpockContextCustomizer@0], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@1e1b512e]; rollback [true]
2022-10-20 11:27:32.296 [TID: N/A] [main] INFO c.m.interceptor.TenancyInterceptor -TenancyInterceptor插入日志信息->KsAMapper.insert->【系统调用】sql : insert into ks_a(name) values ('林')
2022-10-20 11:27:32.298 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -==> Preparing: insert into ks_a(name) values (?)
2022-10-20 11:27:32.316 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -==> Parameters: 林(String)
2022-10-20 11:27:32.365 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -<== Updates: 1
2022-10-20 11:27:32.377 [TID: N/A] [main] INFO c.m.interceptor.TenancyInterceptor -TenancyInterceptor插入日志信息->KsBDao.insert->【系统调用】sql : insert into ks_b(age) values (10)
2022-10-20 11:27:32.377 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsBDao.insert -==> Preparing: insert into ks_b(age) values (?)
2022-10-20 11:27:32.377 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsBDao.insert -==> Parameters: 10(Integer)
2022-10-20 11:27:32.421 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsBDao.insert -<== Updates: 1
2022-10-20 11:27:32.470 [TID: N/A] [main] INFO o.s.t.c.t.TransactionContext -Rolled back transaction for test: [DefaultTestContext@c430e6c testClass = TranTest, testInstance = com.forlan.kaoshi.TranTest@ce0c2b3, testMethod = test@TranTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@312aa7c testClass = TranTest, locations = '{}', classes = '{class com.forlan.kaoshi.KaoshiApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@418e7838, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@3e2e18f2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@48ae9b55, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@72f926e6, org.spockframework.spring.mock.SpockContextCustomizer@0], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]
Rolled back transaction for test,数据都回滚了
解决
1、方法加注解@Rollback(false)
该注解是直接关闭了自动回滚,异常情况下,数据也不会回滚
@Test
@Transactional
@Rollback(false)
public void test(){
......
}
2022-10-20 11:24:36.132 [TID: N/A] [main] INFO o.s.t.c.t.TransactionContext -Began transaction (1) for test context [DefaultTestContext@66982506 testClass = TranTest, testInstance = com.forlan.kaoshi.TranTest@5efa2b92, testMethod = test@TranTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@70cf32e3 testClass = TranTest, locations = '{}', classes = '{class com.forlan.kaoshi.KaoshiApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3e2e18f2, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@3e92efc3, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@30ee2816, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@27ce24aa, org.spockframework.spring.mock.SpockContextCustomizer@0], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@1838e02]; rollback [false]
2022-10-20 11:24:38.073 [TID: N/A] [main] INFO c.m.interceptor.TenancyInterceptor -TenancyInterceptor插入日志信息->KsAMapper.insert->【系统调用】sql : insert into ks_a(name) values ('林')
2022-10-20 11:24:38.077 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -==> Preparing: insert into ks_a(name) values (?)
2022-10-20 11:24:38.113 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -==> Parameters: 林(String)
2022-10-20 11:24:38.134 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -<== Updates: 1
2022-10-20 11:24:38.249 [TID: N/A] [main] INFO c.m.interceptor.TenancyInterceptor -TenancyInterceptor插入日志信息->KsBDao.insert->【系统调用】sql : insert into ks_b(age) values (10)
2022-10-20 11:24:38.249 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsBDao.insert -==> Preparing: insert into ks_b(age) values (?)
2022-10-20 11:24:38.249 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsBDao.insert -==> Parameters: 10(Integer)
2022-10-20 11:24:38.267 [TID: N/A] [main] DEBUG c.m.k.forlan.mapper.KsBDao.insert -<== Updates: 1
2022-10-20 11:24:38.323 [TID: N/A] [main] INFO o.s.t.c.t.TransactionContext -Committed transaction for test: [DefaultTestContext@66982506 testClass = TranTest, testInstance = com.forlan.kaoshi.TranTest@5efa2b92, testMethod = test@TranTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@70cf32e3 testClass = TranTest, locations = '{}', classes = '{class com.forlan.kaoshi.KaoshiApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3e2e18f2, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@3e92efc3, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@30ee2816, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@27ce24aa, org.spockframework.spring.mock.SpockContextCustomizer@0], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]
数据成功入库
2、使用http访问
通过TestRestTemplate 访问controller方法
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class TranTest {
@Test
public void add() throws Exception {
TestRestTemplate restTemplate = new TestRestTemplate();
restTemplate.postForLocation("http://localhost:8100/kaoshi/forlan/test/add", KsA.class);
}
}
@RestController
@RequestMapping("/forlan/test")
public class TestController {
@Autowired
private KsAService ksAService;
@Autowired
private KsBService ksBService;
@PostMapping("/add")
@Transactional
public void add() {
KsA ksA = new KsA();
ksA.setName("林");
ksAService.insert(ksA);
KsB ksB = new KsB();
ksB.setAge(10);
ksBService.insert(ksB);
}
}
2022-10-27 16:10:46.053 [TID: N/A] [http-nio-8100-exec-1] INFO o.a.c.c.C.[.[localhost].[/forlan] -Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-10-27 16:10:46.053 [TID: N/A] [http-nio-8100-exec-1] INFO o.s.web.servlet.DispatcherServlet -Initializing Servlet 'dispatcherServlet'
2022-10-27 16:10:46.158 [TID: N/A] [http-nio-8100-exec-1] INFO o.s.web.servlet.DispatcherServlet -Completed initialization in 105 ms
2022-10-27 16:10:46.211 [TID: N/A] [http-nio-8100-exec-1] INFO c.m.k.common.config.ControllerAspect -request(2666eff88910474a8f0a921c5da76454)【请求方法TestController.add1(),参数:[]】 end
2022-10-27 16:10:46.227 [TID: N/A] [http-nio-8100-exec-1] INFO com.zaxxer.hikari.HikariDataSource -DatebookHikariCP - Starting...
2022-10-27 16:10:46.519 [TID: N/A] [http-nio-8100-exec-1] INFO com.zaxxer.hikari.HikariDataSource -DatebookHikariCP - Start completed.
2022-10-27 16:10:46.577 [TID: N/A] [http-nio-8100-exec-1] INFO c.m.interceptor.TenancyInterceptor -TenancyInterceptor插入日志信息->KsAMapper.insert->租户【系统调用】sql : insert into ks_a(name) values ('林')
2022-10-27 16:10:46.580 [TID: N/A] [http-nio-8100-exec-1] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -==> Preparing: insert into ks_a(name) values (?)
2022-10-27 16:10:46.601 [TID: N/A] [http-nio-8100-exec-1] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -==> Parameters: 林(String)
2022-10-27 16:10:46.615 [TID: N/A] [http-nio-8100-exec-1] DEBUG c.m.k.forlan.mapper.KsAMapper.insert -<== Updates: 1
2022-10-27 16:10:46.627 [TID: N/A] [http-nio-8100-exec-1] INFO c.m.interceptor.TenancyInterceptor -TenancyInterceptor插入日志信息->KsBDao.insert->租户【系统调用】sql : insert into ks_b(age) values (10)
2022-10-27 16:10:46.627 [TID: N/A] [http-nio-8100-exec-1] DEBUG c.m.k.forlan.mapper.KsBDao.insert -==> Preparing: insert into ks_b(age) values (?)
2022-10-27 16:10:46.628 [TID: N/A] [http-nio-8100-exec-1] DEBUG c.m.k.forlan.mapper.KsBDao.insert -==> Parameters: 10(Integer)
2022-10-27 16:10:46.643 [TID: N/A] [http-nio-8100-exec-1] DEBUG c.m.k.forlan.mapper.KsBDao.insert -<== Updates: 1
2022-10-27 16:10:46.670 [TID: N/A] [http-nio-8100-exec-1] INFO c.m.k.common.config.ControllerAspect -request(2666eff88910474a8f0a921c5da76454)end, cost 459ms
数据成功入库
注意:@SpringBootTest需要加上参数(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT),不然会出现下面错误
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8100/kaoshi/forlan/test/add": Connect to localhost:8100 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused: connect; nested exception is org.apache.http.conn.HttpHostConnectException: Connect to localhost:8100 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused: connect
原理
官方文档说明
官方文档说明地址
43.3 Testing Spring Boot applications
@SpringBootTest属性webEnvironment
- Mock(默认) : 加载WebApplicationContext 并提供模拟的web环境 Servlet环境,使用此批注时,不会启动嵌入式服务器
- RANDOM_PORT : 加载WebServerApplicationContext 并提供真实的web环境,嵌入式服务器, 监听端口是随机的
- DEFINED_PORT : 加载WebServerApplicationContext并提供真实的Web环境,嵌入式服务器启动并监听定义的端口(来自 application.properties或默认端口 8080)
- NONE : 使用SpringApplication加载ApplicationContext 但不提供任何Web环境
If your test is , it will rollback the transaction at the end of each test method by default. If you’re using this arrangement in combination with either or , any transaction initiated on the server won’t rollback as the test is running in a different thread than the server processing.@Transactional RANDOM_PORT DEFINED_PORT文章来源:https://www.toymoban.com/news/detail-466782.html
大概意思就是,在单元测试中,加了@Transactional注解,默认情况下,它将在每个测试方法结束时回滚事务。当我们使用RANDOM_PORT或DEFINED_PORT任一作为运行环境,服务器上启动的任何事务都不会回滚,因为测试运行在不同线程中。文章来源地址https://www.toymoban.com/news/detail-466782.html
到了这里,关于单元测试JunitTest加@Transactional事务自动回滚的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!