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

Spring Controller并发处理相同颜色请求时重复创建数据库记录的问题求助

Spring Controller并发处理相同颜色请求时重复创建数据库记录的问题求助

大家好,我遇到了一个Spring并发场景下的数据库重复创建问题,想请各位帮忙分析解决:

我做了一个简单的POST接口,用来接收Car的JSON数据,核心逻辑是:如果请求里的颜色在数据库中已经存在,就直接复用这条颜色记录;如果不存在,就新建一条颜色记录。

控制器代码

@RequestMapping(method = RequestMethod.POST, consumes = { "application/json" })
public Car digest(@RequestBody CarFormat body){
    return CarsService.digest(body.document, body.car);
}

服务层核心方法

在CarsService的digest方法里,我调用了findColorOrCreate方法来处理颜色的查找或创建逻辑:

private Car findColorOrCreate(CarFormat car) {
    String colorReference = car.color.value;
    Assert.notNull(colorReference, String.format("Color reference not found from: %s.", car));
    
    if (colorService.existsByReference(colorReference)) {
        return colorService.findByReference(colorReference);
    }
    return colorService.create(extractColor(car, colorReference));
}

逻辑很直白:先检查颜色是否存在,存在就返回已有记录,不存在就调用create方法新建。

并发测试代码

为了验证并发场景下的行为,我写了一个集成测试,模拟3个几乎同时发送的请求,都用同一个颜色标识"red":

@Test
public void should_createOneColorRecord_whenSimultaneousCalls_Endpoint() throws InterruptedException {
    String sameColorReference = "red";
    String json1 = "...car_id: 1, color:"+sameColorReference+"...";
    String json2 = "...car_id: 2, color:"+sameColorReference+"...";
    String json3 = "...car_id: 3, color:"+sameColorReference+"...";
    String mimeType = "application/json";
    
    CountDownLatch latch = new CountDownLatch(3);
    executeAsyncRequest("/api/", mimeType, json1, latch);
    executeAsyncRequest("/api/", mimeType, json2, latch);
    executeAsyncRequest("/api/", mimeType, json3, latch);
    
    latch.await();
    
    assertThat(entityManager.createQuery("SELECT count(c) FROM Color c WHERE c.reference like '"+sameColorReference+"'").getSingleResult(), equalTo(Long.valueOf(1)));
}

其中executeAsyncRequest方法用不同线程发送请求,模拟真实并发:

private void executeAsyncRequest(String endpoint, String mimeType, String json, CountDownLatch latch) {
    MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post(endpoint)
            .contentType(mimeType)
            .content(json);
    
    new Thread(() -> {
        try {
            this.mockMvc.perform(builder)
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    .andDo(MockMvcResultHandlers.print());
            latch.countDown();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }).start();
}

遇到的问题

测试的预期结果是数据库中只创建1条"red"颜色记录,但实际运行后却创建了3条。我尝试过在控制器、服务层甚至接口上添加@Transactional注解,也试过@Transactional(propagation = Propagation.REQUIRES_NEW),但都没能解决重复创建的问题。

有没有朋友能帮我分析一下问题出在哪,以及该怎么解决呢?非常感谢!

备注:内容来源于stack exchange,提问作者NicoESIEA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 09:10:27