You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot测试中提交变更并在测试后回滚?

解决方案:通过flush触发数据库约束,同时保留事务回滚

你的核心矛盾在于:默认事务下JPA延迟写入导致唯一约束不生效,而取消事务后数据无法回滚。解决思路是保留@DataJpaTest的默认事务行为(测试后自动回滚),同时强制同步持久化上下文到数据库,触发约束检查。

具体步骤

  1. 移除类级别上的@Transactional(propagation = Propagation.NOT_SUPPORTED)注解,恢复每个测试方法的独立事务(默认测试结束后自动回滚)。
  2. 在需要验证唯一约束的测试中,使用saveAndFlush()替代save(),或在save()后调用flush(),强制将变更同步到数据库,触发唯一约束校验。

修改后的测试类代码

package com.example.springdata.repositories;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.util.Optional;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.dao.DataIntegrityViolationException;

import com.example.springdata.entities.UserEntity;

import io.zonky.test.db.AutoConfigureEmbeddedDatabase;
import io.zonky.test.db.AutoConfigureEmbeddedDatabase.DatabaseProvider;

@DataJpaTest
@AutoConfigureEmbeddedDatabase(provider = DatabaseProvider.ZONKY)
class UserRepositoryIntegrationTests {

    @Autowired
    private UserRepository userRepository;

    @Test
    void userIsCreatedAndRead() {
        UserEntity user = createEntity1();
        userRepository.save(user);

        assertThat(user.getId()).isNotNull();

        Optional<UserEntity> optionalUser = userRepository.findById(user.getId());
        assertThat(optionalUser).isPresent();

        optionalUser.ifPresent(foundUser -> assertThat(foundUser).usingRecursiveComparison().isEqualTo(user));
    }

    @Test
    void emailIsUnique() {
        UserEntity user1 = createEntity1();
        // 保存并立即同步到数据库,触发约束检查
        userRepository.saveAndFlush(user1);

        UserEntity user2 = createEntity2();
        user2.setEmail(user1.getEmail());
        // 再次保存并同步,触发重复邮箱的约束异常
        assertThrows(DataIntegrityViolationException.class, () -> userRepository.saveAndFlush(user2));
    }

    private UserEntity createEntity1() {
        UserEntity user = new UserEntity();
        user.setLogin("john");
        user.setFirstName("John");
        user.setLastName("Doe");
        user.setEmail("john.doe@example.com");
        return user;
    }

    private UserEntity createEntity2() {
        UserEntity user = new UserEntity();
        user.setLogin("jane");
        user.setFirstName("Jane");
        user.setLastName("Smith");
        user.setEmail("jane.smith@example.com");
        return user;
    }

}

原理说明

  • @DataJpaTest默认会给每个测试方法创建独立事务,测试结束后自动回滚,保证测试间数据隔离。
  • JPA默认延迟写入:save()仅将实体放入持久化上下文,不会立即执行SQL。saveAndFlush()会强制将待处理的SQL发送到数据库,触发唯一约束校验。
  • 这样既保证了emailIsUnique测试能触发数据库异常,又让每个测试结束后数据自动回滚,不会影响其他测试用例。

内容的提问来源于stack exchange,提问作者Denis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 09:54:20