单元测试JunitTest加@Transactional事务自动回滚

这篇具有很好参考价值的文章主要介绍了单元测试JunitTest加@Transactional事务自动回滚。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题

在测试事务传播行为的时候,使用单位测试加了@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,数据都回滚了
单元测试JunitTest加@Transactional事务自动回滚
单元测试JunitTest加@Transactional事务自动回滚

解决

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]]

数据成功入库
单元测试JunitTest加@Transactional事务自动回滚
单元测试JunitTest加@Transactional事务自动回滚

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

数据成功入库
单元测试JunitTest加@Transactional事务自动回滚
单元测试JunitTest加@Transactional事务自动回滚

注意:@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

大概意思就是,在单元测试中,加了@Transactional注解,默认情况下,它将在每个测试方法结束时回滚事务。当我们使用RANDOM_PORT或DEFINED_PORT任一作为运行环境,服务器上启动的任何事务都不会回滚,因为测试运行在不同线程中。文章来源地址https://www.toymoban.com/news/detail-466782.html

到了这里,关于单元测试JunitTest加@Transactional事务自动回滚的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring声明式事务@Transactional的一些问题的测试及求证

    前提:有两个方法,a方法对a表做修改操作,b方法对b表做修改操作 a方法调用b方法,然后a方法报错,伪代码如下 a方法调用b方法,然后b方法报错,伪代码如下 直接上结果: √:数据库插入成功 ×:数据库插入失败 在 Spring Boot 中,默认情况下,对于单个数据库操作(即单个

    2024年02月14日
    浏览(37)
  • springboot Junit单元测试默认事务不提交

    因为以前总觉得Junit单元测试配置比较繁琐,代码功能大多使用main方法或者postman测试,直到最近才使用单元测试,在测试过程中遇到了事务不提交的问题,一直以为是代码问题,后来才直到单元测试 默认不提交事务 ,记录下来,防止以后再次踩坑。 如上,入库操作不会实现

    2024年02月10日
    浏览(40)
  • Spring使用@Transactional 管理事务,Java事务详解。

    B站视频:https://www.bilibili.com/video/BV1eV411u7cg 技术文档:https://d9bp4nr5ye.feishu.cn/wiki/HX50wdHFyiFoLrkfEAAcTBdinvh 简单来说事务就是一组对数据库的操作 要么都成功,要么都失败。 事务要保证可靠性,必须具备四个特性:ACID。 A:原子性:事务是一个原子操作单元,要么完全执行,要么

    2024年02月11日
    浏览(31)
  • Spring 事务(编程式事务、声明式事务@Transactional、事务隔离级别、事务传播机制)

    本篇重点总结: 在 Spring 项目中使用事务,有两种方式:编程式手动操作和声明式自动提交,声明式自动提交使用最多,只需要在方法上添加注解 @Transactional 设置事务的隔离级别 @Transactional(isolation = Isolation.SERIALIZABLE),Spring 中的事务隔离级别有5种 设置事务的传播机制 @Tra

    2024年02月03日
    浏览(44)
  • 使用注解新开事务 @Transactional

    使用注解新开事务

    2024年02月07日
    浏览(36)
  • 关于事务@Transactional

    添加事务注解的主要目的是确保在数据库操作过程中的一致性和隔离性。事务是一组操作被视为一个单独的工作单元,并且要么完全成功提交,要么完全回滚,以确保数据的一致性。事务注解提供了在方法或类级别上声明事务边界的方式,以便框架能够自动管理事务。 以下是

    2024年02月14日
    浏览(40)
  • Transactional事务失效场景汇总

    作为后端程序员,在日常开发中,经常会遇到事务处理的场景,在Spring中,为了更好的支撑我们进行数据库操作,它提供了两种事务管理的方式: 编程式事务 声明式事务 那众所周知,我们平时用的最多的就是 声明式事务 ,也就是使用**@Transactional**注解的方式了 但是在日常

    2024年02月01日
    浏览(41)
  • Spring的事务(@Transactional)

    Spring事务的本质,其实就是通过 Spring AOP 切面技术 Spring事务支持2种使用方式 声明式事务(注解方式) 编程式事务(代码方式):代码需要手动控制,比较繁琐,一般不使用 SpringBoot 默认开启了事务 Spring Spring的事务是使用AOP来实现的,在执行目标方法的前和后,加上了事务

    2024年02月21日
    浏览(47)
  • 事务@transactional执行产生重复数据

    系统设计之初,每次来新请求,业务层会先查询数据库,判断是否存在相同的id数据(id是唯一标识产品的),有则返回当前数据库查到的数据,根据数据决定下一步动作,没有则认为是初次请求,将数据存入数据库,执行另一个操作。结果最近出现了并发情况下数据库产生了

    2024年02月16日
    浏览(50)
  • Spring——事务注解@Transactional【建议收藏】

    在某些业务场景下,如果一个请求中,需要同时写入多张表的数据或者执行多条sql,为了保证操作的原子性(要么同时成功,要么同时失败),避免数据不一致的情况,我们一般都会用到事务;Spring框架下,我们经常会使用@Transactional注解来管理事务; 本篇介绍Spring的事务注

    2024年02月03日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包