2

我正在使用 junit-jupiter 编写集成测试,并且发生了一些非常奇怪的事情 - >当我阅读时发生约束冲突异常(不保存数据)

storesTemplateRepository.findByCountryOrderByTemplateName(country, pageable);引发以下异常:

could not execute statement; SQL [n/a]; constraint ["PRIMARY KEY ON PUBLIC.STORES_TEMPLATE(ID)"; SQL statement:
insert into stores_template (country, stores, template_name, id) values (?, ?, ?, ?) [23505-196]]

实体:

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "STORES_TEMPLATE")
public class StoresTemplate {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "STORES_TEMPLATE_ID_SEQ")
    @SequenceGenerator(name = "STORES_TEMPLATE_ID_SEQ", sequenceName = "STORES_TEMPLATE_ID_SEQ", allocationSize = 1)
    private long id;

    @Enumerated(EnumType.STRING)
    private CountryEnum country;

    private String templateName;

    @Lob
    private String stores;

    public void setStores(List<String> stores) {
        this.stores = String.join(",", stores);
    }

    @JsonIgnore
    public List<String> getStoresAsList() {
        return Arrays.stream(stores.split(","))
                .distinct()
                .collect(Collectors.toList());
    }

}

测试

@Slf4j
@Transactional
@SpringBootTest
public class StoresTemplateControllerTest {

    @Autowired
    private WebApplicationContext context;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private StoresTemplateRepository storesTemplateRepository;

    private MockMvc mockMvc;

    @BeforeEach
    public void setUp() {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(SecurityMockMvcConfigurers.springSecurity())
                .build();
    }

    @Test
    public void fullApiTest() {
        OAuth2AuthenticationToken dePrincipal = new TestDataBuilder()
                .createOAuth2AuthenticationToken()
                .setDefaultStoreUser()
                .setRoles(SiamRoles.DE_CREATOR_ADMIN)
                .build();

        CreateStoresTemplateDto createStoresTemplateDeDto = CreateStoresTemplateDto.builder()
                .country(CountryEnum.DE)
                .stores(List.of("de1000", "de1100"))
                .templateName("de template")
                .build();

        CreateStoresTemplateDto createStoresTemplateBgDto = CreateStoresTemplateDto.builder()
                .country(CountryEnum.BG)
                .stores(List.of("bg2000", "bg2100"))
                .templateName("bg template")
                .build();

        CreateStoresTemplateDto createStoresTemplateDefaultDto = CreateStoresTemplateDto.builder()
                .country(null)
                .stores(List.of("de3000", "de3100"))
                .templateName("default template")
                .build();

        try {

            // find all existing by predefined insertion script
            for (long id: findAll(dePrincipal, CountryEnum.DE).map(e -> e.id)) {
                storesTemplateRepository.deleteById(id);
            }


            storesTemplateRepository.save(StoresTemplateMapper.toStoresTemplate(createStoresTemplateDeDto));
            storesTemplateRepository.findByCountryOrderByTemplateName(CountryEnum.DE);

            storesTemplateRepository.save(StoresTemplateMapper.toStoresTemplate(createStoresTemplateBgDto));
            storesTemplateRepository.findByCountryOrderByTemplateName(CountryEnum.DE); // Here the exception occurs

            storesTemplateRepository.save(StoresTemplateMapper.toStoresTemplate(createStoresTemplateDefaultDto));
            storesTemplateRepository.findByCountryOrderByTemplateName(CountryEnum.DE);
            

        } catch (Exception e) {
            e.printStackTrace();
            fail(e.getMessage());
        }
    }

}
4

1 回答 1

2
  • JPA/尽可能Hibernate将操作排队,不会立即调用数据库,然后在事务完成之前,根据类型对这些操作进行排序并执行它们。这在休眠session中称为。Transactional write-behind正如你所看到的,即使你先调用了 delete,如果它在排队,hibernate 也会把它排在最后。

    1. 插入,按执行顺序
    2. 更新
    3. 删除集合元素
    4. 集合元素的插入
    5. 删除,按执行顺序
  • 因此,即使您首先删除,正如您所看到的那样,hibernate 也会最后删除。如果你想控制订单,你需要刷新它。所以请执行以下操作。

    for (long id: findAll(dePrincipal, CountryEnum.DE).map(e -> e.id)) {
        storesTemplateRepository.deleteById(id);
    }
    storesTemplateRepository.flush();

参考

于 2020-08-04T07:46:26.497 回答