Spring Data Cassandra Reactive批量插入带TTL抛出CodecNotFoundException
问题原因分析
你遇到的错误核心是误用了BatchOperations.insert方法:Spring Data Cassandra的BatchOperations.insert并没有提供(实体对象, InsertOptions)的重载方法,你传入的InsertOptions.builder().ttl(...)被框架当成了另一个需要插入的实体对象,进而尝试将InsertOptions.Builder映射为Cassandra表,生成了错误的INSERT INTO insertoptionsbuilder...语句,最终引发Codec找不到的异常。此外你还遗漏了InsertOptions.builder()的build()调用,没有生成有效的配置实例。
解决方案
针对单个实体需要独立TTL的场景,提供两种可行的解决方式:
方案一:拆分独立Insert操作(推荐)
因为批量操作(Batch)的配置默认是全局生效的,若需要给不同插入设置差异化选项,更合理的方式是单独执行每个Insert操作并配置各自的选项,再通过Mono.when合并操作确保全部执行成功。
代码示例:
// 分别定义每个插入操作,按需配置选项 Mono<WriteResult> doctorInsert = reactiveCassandraTemplate.insert(doctorFromEvent(event, image)); Mono<WriteResult> specialityInsert = reactiveCassandraTemplate.insert(doctorBySpecialityFromEvent(event, image)); Mono<WriteResult> locationInsert = reactiveCassandraTemplate.insert(locationFromEvent(event, image)); Mono<WriteResult> processedEventInsert = reactiveCassandraTemplate.insert( new ProcessedEvent(event.id()), InsertOptions.builder().ttl(Duration.ofDays(30)).build() // 注意调用build()生成配置实例 ); // 合并所有操作,确保全部执行完成 return Mono.when(doctorInsert, specialityInsert, locationInsert, processedEventInsert) .handle((unused, sink) -> sink.next(Done.getInstance())) .onErrorMap(e -> new RuntimeException("批量插入失败", e));
方案二:使用Batch手动构建带TTL的语句
若必须使用Batch操作,可通过statement方法手动构建带TTL的CQL插入语句,将其加入批量操作中:
代码示例:
return reactiveCassandraTemplate.batchOps() .insert(doctorFromEvent(event, image)) .insert(doctorBySpecialityFromEvent(event, image)) .insert(locationFromEvent(event, image)) // 手动构建带TTL的插入语句并加入Batch .statement(reactiveCassandraTemplate.getCqlOperations().insert( new ProcessedEvent(event.id()), InsertOptions.builder().ttl(Duration.ofDays(30)).build() )) .execute() .handle((writeResult, sink) -> { if (writeResult.wasApplied()) { sink.next(Done.getInstance()); return; } sink.error(new RuntimeException("WriteResult.wasApplied was false, something bad happened")); });
内容的提问来源于stack exchange,提问作者Milad Amery
相关产品推荐
相关产品推荐

