【问题标题】:Spring Data MongoDB @Transactional isn't working?Spring Data MongoDB @Transactional 不起作用?
【发布时间】:2020-02-11 22:26:20
【问题描述】:

我有以下 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,并将其注入我的测试类。下面是我创建的服务 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();
    }

}

和我注入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,将回滚保存的用户,但在调用后用户仍然会保留在数据库中。

【问题讨论】:

标签: spring-data spring-data-mongodb


【解决方案1】:

事实证明@DataMongoTest 没有激活 MongoDB 事务的自动配置。我已经用 Spring Boot 提交了a ticket 来解决这个问题。同时,您可以通过添加来使其工作

@ImportAutoConfiguration(TransactionAutoConfiguration.class)

到你的测试班。

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

之前的问题提出了一个略有不同的代码安排,它受到其他问题的影响。作为参考,这是以前的答案:

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

你的例子有两个问题:

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

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

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

【讨论】:

    猜你喜欢
    • 2020-03-15
    • 2013-12-10
    • 2012-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多