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

插入数据后查询数据出现随机缺失的异常问题排查

问题描述

我用Spring Boot构建了一套CRUD REST API,通过Spring Initializr创建项目并引入spring-boot-starter-data-couchbase依赖。我自己通过CouchbaseTemplate实现了Repository的部分方法,比如findAll:

@Override
public List<Customer> findAll() {
    List<JsonObject> jsonObjects = couchbaseTemplate.getCouchbaseClientFactory().getScope()
            .query(String.format("SELECT * FROM %1$s ", keySpace)).rowsAsObject();
    return jsonObjects.stream().map(this::mapJsonToCustomer).collect(Collectors.toList());
 }

同时用Testcontainers编写了测试用例:

@Test
public void testFindAll() {
    Customer alex = new Customer("customer1", "Alex", "Stone");
    Customer jack = new Customer("customer2", "Jack", "Sparrow");
    List<Customer> customerList = List.of(alex, jack);
    Transactions transactions = couchbaseTemplate.getCouchbaseClientFactory().getCluster().transactions();
    customerList.forEach(customer ->
            transactions.run(ctx -> ctx.insert(collection, customer.getId(), customer)
            )
    );
    List<Customer> customers = customerRepository.findAll();
    Assertions.assertEquals(customerList, customers);
}

现在遇到的问题是:通过事务插入两条数据后,调用customerRepository.findAll查询时,测试偶尔会失败,只能查到一条数据;但在调试模式下测试完全正常。我以为是同步问题,尝试过同步方法,但没解决。请问哪里操作错了?


问题原因与解决办法

这个问题核心是Couchbase事务提交与N1QL查询的一致性延迟——调试模式下因为断点停顿,给了事务足够的同步时间,所以查询正常;正常测试时执行速度快,事务的变更还没同步到查询引擎,就导致查不全数据。

具体原因

你用Couchbase事务插入数据,但Couchbase默认是最终一致性:事务提交后,数据不会立刻对N1QL查询可见。当测试执行速度快时,可能其中一条数据还没完成索引同步,就被查询了,所以只返回一条。

解决办法

  1. 查询时指定强一致性级别
    修改findAll方法的查询,加上REQUEST_PLUS一致性参数,强制查询最新的已提交数据:
@Override
public List<Customer> findAll() {
    QueryOptions options = QueryOptions.queryOptions().consistency(QueryScanConsistency.REQUEST_PLUS);
    List<JsonObject> jsonObjects = couchbaseTemplate.getCouchbaseClientFactory().getScope()
            .query(String.format("SELECT * FROM %1$s ", keySpace), options).rowsAsObject();
    return jsonObjects.stream().map(this::mapJsonToCustomer).collect(Collectors.toList());
 }

这个参数会确保查询能看到所有已提交的变更,适合测试场景或者需要强一致性的业务场景。

  1. 优化事务写法(可选)
    你现在是循环调用transactions.run,相当于每个插入都是单独的事务,建议把两个插入放在同一个事务里,保证原子性:
transactions.run(ctx -> {
    ctx.insert(collection, alex.getId(), alex);
    ctx.insert(collection, jack.getId(), jack);
    return null;
});
  1. 不推荐:测试中加等待(仅临时方案)
    如果不想修改查询逻辑,也可以在插入后加短暂等待,给索引同步留时间,但这种方法不稳定,不同环境下需要调整时长:
// 插入数据后等待
try {
    Thread.sleep(500);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}
List<Customer> customers = customerRepository.findAll();

额外提醒

生产环境如果不需要强一致性,尽量别用REQUEST_PLUS,会影响查询性能;但测试场景为了保证正确性,用它完全没问题。如果不需要自定义N1QL逻辑,直接用Spring Data Couchbase提供的CouchbaseRepository默认findAll方法,它会自动处理一致性问题,比自己写的更可靠。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 05:37:10