GoCQL查询Cassandra bigint列传[]int64到IN()报编组错误求助
问题原因
gocql驱动默认不会将IN (?)中的单个?占位符自动匹配为切片类型的多值参数,默认会把这个占位符对应的值当作单个bigint类型处理。直接传入[]int64切片时,驱动会尝试将整个切片序列化成为单个bigint值,就会抛出can not marshal []int64 into bigint错误。
解决方案
你可以任选以下两种方式修复:
方案1:使用gocql原生In包装器(推荐)
不需要修改你原来写的CQL语句,只需要在传参时用gocql.In()把切片参数包装起来,驱动会自动完成占位符展开和参数绑定,代码改动最小:
// 原QUERY定义保持不变 query := db.CassandraSession.Query(QUERY, gocql.In(Ids1), gocql.In(Ids2))
后续的Iter、Scan逻辑不需要做任何改动。
方案2:手动动态生成占位符
如果是极老旧的不支持In包装器的gocql版本,可以根据传入切片的长度,动态生成对应数量的?占位符,再把切片元素拆成独立参数传入:
import ( "fmt" "strings" ) // 提前判空,避免生成IN ()非法语法 if len(Ids1) == 0 || len(Ids2) == 0 { // 处理空参数逻辑,直接返回空结果即可 } // 构造id1对应的占位符和参数列表 id1Ph := make([]string, len(Ids1)) id1Args := make([]interface{}, len(Ids1)) for i, id := range Ids1 { id1Ph[i] = "?" id1Args[i] = id } // 构造id2对应的占位符和参数列表 id2Ph := make([]string, len(Ids2)) id2Args := make([]interface{}, len(Ids2)) for i, id := range Ids2 { id2Ph[i] = "?" id2Args[i] = id } // 拼接最终查询语句 finalQuery := fmt.Sprintf(`SELECT column1,column2,column3 FROM tableName WHERE id1 IN (%s) AND id2 IN (%s) ALLOW FILTERING;`, strings.Join(id1Ph, ","), strings.Join(id2Ph, ",")) // 合并所有参数执行查询 allArgs := append(id1Args, id2Args...) query := db.CassandraSession.Query(finalQuery, allArgs...)
注意事项
- 两种方案都需要提前判断传入的Id切片长度,不能传空切片,否则会生成
IN ()的非法CQL语法,Cassandra会直接返回语法错误。 - 查询中使用了
ALLOW FILTERING,如果表数据量较大,该查询会触发全表扫描,性能很差。生产环境建议优化表的分区键、聚类键设计,或者给对应字段建索引,尽量避免使用ALLOW FILTERING。
内容的提问来源于stack exchange,提问作者Surabhi Bobade
相关产品推荐
相关产品推荐

