如何使用QueryBuilder/CassandraTemplate向Cassandra动态表插入Map<String,Object>数据
可行实现方案
方案1:基于原生QueryBuilder实现
之前的update方案错误原因是错误遍历了Map.class的反射字段,而非Map中存储的业务键值对,导致生成的赋值语句完全不符合预期。正确的插入实现直接遍历Map的键值对,调用literal()方法将Object类型值转换为QueryBuilder要求的Term类型即可:
import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; @Component public class DynamicCassandraDao { @Autowired private CqlSession cqlSession; public int save(String tableName, Map<String, Object> dataMap) { // 参数合法性校验 if (tableName == null || tableName.isBlank() || dataMap == null || dataMap.isEmpty()) { return 0; } RegularInsert insertBuilder = QueryBuilder.insertInto(tableName); // 遍历业务键值对构造插入语句 for (Map.Entry<String, Object> entry : dataMap.entrySet()) { if (entry.getValue() != null) { insertBuilder = insertBuilder.value(entry.getKey(), QueryBuilder.literal(entry.getValue())); } } // 执行语句,返回执行结果 boolean execResult = cqlSession.execute(insertBuilder.build()).wasApplied(); return execResult ? 1 : 0; } }
literal()方法会自动完成Java类型到Cassandra数据类型的映射,不需要单独对Long等类型做特殊判断。
方案2:基于CassandraTemplate实现
如果使用Spring Data Cassandra框架,借助CassandraTemplate可以进一步简化实现:
import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import java.util.Map; import java.util.stream.Collectors; @Component public class DynamicCassandraService { @Autowired private CassandraTemplate cassandraTemplate; public int save(String tableName, Map<String, Object> dataMap) { if (tableName == null || tableName.isBlank() || dataMap == null || dataMap.isEmpty()) { return 0; } // 批量构造键值对映射 Map<String, com.datastax.oss.driver.api.querybuilder.term.Term> termMap = dataMap.entrySet().stream() .filter(entry -> entry.getValue() != null) .collect(Collectors.toMap( Map.Entry::getKey, entry -> QueryBuilder.literal(entry.getValue()) )); SimpleStatement insertStatement = QueryBuilder.insertInto(tableName) .values(termMap) .build(); // 执行并返回结果 return cassandraTemplate.getCqlOperations().execute(insertStatement) ? 1 : 0; } }
注意事项
- 传入的
dataMap必须包含目标表的所有主键列,否则Cassandra会抛出主键缺失的执行异常 - 如果需要实现upsert逻辑(存在则更新、不存在则插入),只需在插入构造时追加
.ifNotExists()即可,用法和标准CQL一致 - 返回值规则可根据业务需求调整,如需返回错误码可捕获执行异常后返回对应数值即可
内容的提问来源于stack exchange,提问作者Narupo
相关产品推荐
相关产品推荐

