Junit4 spring注解事务不会滚问题

本文通过一系列实验探讨了在JUnit4测试环境中使用Spring事务管理时的行为差异,特别是@Rollback注解的作用及其与内部方法中事务注解的交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

这事儿吧,机缘巧合。我的项目是用springboot搭建的,junit用的4.12。最近在进行RabbitMQ相关功能的测试,打算测下nginx对消息队列的负载和集群本身的可用,想着,如果client调用失败了,就把插入的数据回滚掉,于是就配置了注解事务,然后,坑就出现了。

状态介绍

注解的配置如下,很常规:

    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- enable transaction annotation support -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>

测试类大概如下:

/**
 * @author nature
 * @create 2018-01-09 14:35
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class MessageQueueDaoTest {

	@Test
	@Transactional
	//@Rollback(false)
	public void testTransaction(){
		//FblockContext.getBean(TransactionTest.class).test();//FblockContext是我自己封装的spring上下文,这个getBean就是spring的,TransactionTest类源码在后面

		MessageQueueDao messageQueueDao= FblockContext.getBean(MessageQueueDao.class);

		RabbitMQRecord record=new RabbitMQRecord();
		record.setId(KeyWorker.nextId());
		record.setRecordType(0);
		record.setRemark("testTransaction单元测试");

		messageQueueDao.insertRabbitMQRecord(record);

		throw new MessageQueueTestException("异常出现,需要回滚。");
	}

}

/**
 * @author nature
 * @create 2018-01-10 12:52
 */
@Component
public class TransactionTest {

	@Transactional
	public void test(){

		MessageQueueDao messageQueueDao= FblockContext.getBean(MessageQueueDao.class);
		RabbitMQRecord record=new RabbitMQRecord();
		record.setId(KeyWorker.nextId());
		record.setRecordType(0);
		record.setRemark("testTransaction单元测试");

		messageQueueDao.insertRabbitMQRecord(record);
		throw new MessageQueueTestException("异常出现,需要回滚。");

	}
}

问题描述

上述代码其实就是我最初的代码,在测试方法类上打了@Transactional,内部抛出异常,然后期望回滚。结果也如我所愿,确实数据库里没插进去。然后,我说试试不抛出异常的,能不能插进去吧。结果也没插进去。。。。见了鬼了。查了半天,我一直以为是我的事务配置不对,于是我写了TransactionTest类,结果表现都是正常的,有异常回滚,无异常不会滚。机缘巧合,让我带了junit关键字去查询,找到了罪魁祸首。
  在junit中有个注解是@Rollback,这个,默认是true,也就是,只要是我配置了注解,就会回滚,不管有没有异常。这个注解可以设置成false,@Rollback(false),那就变成了不管有没有异常都不会滚——蛋好疼。于是做了下面一组测试,具体探明下具体的规则吧,毕竟在做测试,没时间根源码了,前面说了在MessageQueueDaoTest内操作数据库的情况,其实如果MessageQueueDaoTest不配置事务,TransactionTest里面打事务注解,就是我们期待的结果了,为了探明规则,测过的接下来就不试了,接下来的数据库操作都在,TransactionTest内,MessageQueueDaoTest通过获取bean获取实例。

测试

  • MessageQueueDaoTest有事务注解,TransactionTest有事务注解,无异常,这个结果是回滚的,那有有异常的我们不试了,肯定也回滚。
  • MessageQueueDaoTest有事务注解,TransactionTest无事务注解,无异常,这个结果也是回滚的,有异常的也就不试了,肯定也回滚。
      只要外面异常,里面都回滚,那我们试试@Rollback(false)的呢。
  • MessageQueueDaoTest有事务注解,@Rollback(false),TransactionTest有事务注解,无异常,不会滚
  • MessageQueueDaoTest有事务注解,@Rollback(false),TransactionTest有事务注解,有异常,回滚了。但是,按照Rollback的尿性,应该不会滚呀。于是推测,在里面有事务注解,按照自己的规则,拦截了异常回滚了,没有轮到Rollback生效。为了证实我们的猜测,我们把异常挪到MessageQueueDaoTest中去抛出
  • MessageQueueDaoTest有事务注解,@Rollback(false),TransactionTest有事务注解,MessageQueueDaoTest抛异常 ,没有回滚,与我们的猜测一致

结论

junit4的测试类中打事务注解,默认会按照@Rollback(true)来进行处理,无论如何都会回滚,里面调用的方法打不打事务注解已经不重要了。而@Rollback(false)之后,似乎,也只控制在该层方法中出现的异常,就好像是这一层没有打事务似的,而不会传播到嵌套的事务内。根据上面的推测,我怀疑@Rollback(true)时想要提交,里面的传播级别就必须变成会新开事务的,这个,我这次就不证实了。
  此篇博客,今证明,在下填过此坑了。。。。好了,下一个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

征途无悔

发文不易,谢谢认可

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值