Spring Data MongoDB @Transactional не работает? - PullRequest
0 голосов
/ 12 февраля 2020

У меня ниже 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 и имею это введено в мой тестовый класс. Ниже представлен служебный компонент, который я создал:

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

@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, откатывает сохраненного пользователя, но пользователь все еще сохраняется в базе данных после вызова.

1 Ответ

1 голос
/ 12 февраля 2020

Оказывается, что @DataMongoTest не активирует автоматическую настройку транзакций MongoDB. Я подал тикет в Spring Boot, чтобы это исправить. В то же время вы можете заставить это работать, добавив

@ImportAutoConfiguration(TransactionAutoConfiguration.class)

к вашему тестовому классу.

Обратите внимание, что использование транзакций MongoDB требует настройки базы данных набора реплик. Если это не дано, создание транзакции завершится неудачно, и ваш тестовый случай перехватит это исключение, и тест все равно будет успешным. Данные не будут вставлены, но это не из-за брошенного RuntimeException, а из-за того, что транзакция не была запущена в первую очередь.

Ранее в этом вопросе было несколько иное расположение кода, из-за которого возникли другие проблемы. Для справки приведем предыдущий ответ:

@Transactional необходимо использовать в publi c методах отдельного bean-компонента Spring, поскольку транзакционные логи c реализуются путем переноса цели объект с прокси-сервером, который содержит перехватчик, взаимодействующий с инфраструктурой транзакций.

В вашем примере есть две проблемы:

  1. Сам тест не является компонентом Spring. Т.е. к 1023 * не добавлено транзакционное поведение. @Transactional может использоваться в методах тестирования JUnit, но это контролирует транзакционное поведение теста. Наиболее важно откатить транзакцию, чтобы убедиться, что изменения в хранилище данных, сделанные в тесте, не влияют на другие тесты. См. этот раздел справочной документации.

  2. Даже если бы к 1010 * применялись транзакционные логи c, локальный вызов метода никогда не будет вызвать его, поскольку он не пропускает прокси, который его применяет. Подробнее об этом см. В справочную документацию .

Решение вашей проблемы - создать отдельный компонент Spring, который содержит аннотацию @Transactional, получить инъекцию в ваш тестовый пример и вызовите метод из теста.

...