Spring 数据 MongoDB @Transactional 不起作用?

Spring Data MongoDB @Transactional isn't working?

我已经设置了以下 maven 依赖项和配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
@Configuration
@EnableMongoAuditing
public class MongoConfig {

    @Bean
    MongoTransactionManager transactionManager(MongoDbFactory mongoDbFactory) {
        return new MongoTransactionManager(mongoDbFactory);
    }
}

已更新:我已经采用了建议的解决方案来使用 @Transactional 创建一个 bean,并将其注入到我的测试 class 中。下面是我创建的服务 bean:

@Service
@Transactional
@RequiredArgsConstructor
public class MongoTransactionService {

    private final UserRepo userRepo;

    public void boundToFail() throws RuntimeException {
        userRepo.save(User.builder().id("1").build());
        throw new RuntimeException();
    }

}

并测试 class 我注入一个 MongoTransactionService:

的 bean
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class,
        includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MongoTransactionService.class))
@ExtendWith(SpringExtension.class)
class MongoTransactionServiceTest {

    @Autowired
    UserRepo userRepo;

    @Autowired
    MongoTransactionService mongoTransactionService;

    @Test
    void testTransactional() {
        try {
            mongoTransactionService.boundToFail();
        } catch (Exception e) {
            // do something
        }
        val user = userRepo.findById("1").orElse(null);
        assertThat(user).isNull();
    }

}

我期待对 boundToFail() 的调用,它抛出 RuntimeException,将回滚已保存的用户,但调用后用户仍保留在数据库中。

原来 @DataMongoTest 没有激活 MongoDB 事务的自动配置。我已将 a ticket 与 Spring 引导一起提交以修复该问题。同时,您可以通过添加

来让它工作
@ImportAutoConfiguration(TransactionAutoConfiguration.class)

你的测试class。

请注意,使用 MongoDB 事务需要副本集数据库设置。如果没有给出,事务的创建将失败并且您的测试用例将捕获该异常并且测试仍然会成功。数据不会被插入,但这不是因为 RuntimeException 被抛出,而是事务没有首先启动。

该问题之前提出的代码安排略有不同,但存在其他问题。作为参考,这是以前的答案:

@Transactional 需要依赖于单独 Spring bean 的 public 方法,因为事务逻辑是通过包装目标对象实现的使用包含与事务基础结构交互的拦截器的代理。

你的例子有两个问题:

  1. 测试本身不是 Spring bean。 IE。 boundToFail(…) 中没有添加任何交易行为。 @Transactional 可用于 JUnit 测试方法,但它控制着测试的事务行为。最突出的是,回滚事务以确保在测试中对数据存储所做的更改不会影响其他测试。请参阅参考文档的 this section

  2. 即使 boundToFail(…) 应用了事务逻辑,对该方法的本地方法调用也永远不会触发它,因为它没有传递应用它的代理。在 the reference documentation.

  3. 中查看更多信息

您的问题的解决方案是创建一个带有 @Transactional 注释的单独 Spring bean,将其注入您的测试用例并从测试中调用该方法。