aws-sdk-go-v2操作DynamoDB时ExclusiveStartKey分页不生效如何解决?
问题核心原因
传入的ExclusiveStartKey不符合DynamoDB的校验规则,被服务端直接忽略,因此每次扫描都从表的起始位置开始,返回第一条数据和你传入的key匹配。
常见触发场景
- 表使用复合主键(分区键+排序键),但构造
ExclusiveStartKey时只传入了分区键id,缺少排序键属性。DynamoDB要求ExclusiveStartKey必须包含完整主键属性:单主键仅需传分区键,复合主键必须同时传入分区键和排序键,属性不全时会直接忽略该参数。 - 序列化key的结构体属性名、
dynamodbav标签和表主键的属性名不匹配,导致序列化出的key不符合服务端要求。 - 若Scan时指定了
IndexName使用二级索引查询,ExclusiveStartKey需要使用索引对应的键属性,而非原表主键,否则也会被忽略。
修复方案
方案1:补全主键属性
首先确认表主键结构,构造ExclusiveStartKey时补全所有必填属性。以复合主键(id为分区键,created_at为排序键)为例:
// 调整结构体包含所有主键属性 type PaginateKey struct { ID string `dynamodbav:"id" json:"id"` CreatedAt int64 `dynamodbav:"created_at" json:"created_at"` }
方案2:直接透传序列化后的key(更稳妥)
不要手动拼接key,将上一次查询返回的LastEvaluatedKey序列化后传递给前端,前端下次请求时原封不动传回,再反序列化为ExclusiveStartKey使用,可兼容所有主键结构:
import "encoding/base64" import "encoding/json" // 将DynamoDB返回的LastEvaluatedKey转为前端可用的base64字符串 func EncodeLastKey(key map[string]types.AttributeValue) (string, error) { if key == nil { return "", nil } jsonBytes, err := json.Marshal(key) if err != nil { return "", err } return base64.StdEncoding.EncodeToString(jsonBytes), nil } // 将前端传回的base64字符串解析为ExclusiveStartKey func DecodeLastKey(keyStr string) (map[string]types.AttributeValue, error) { if keyStr == "" { return nil, nil } jsonBytes, err := base64.StdEncoding.DecodeString(keyStr) if err != nil { return nil, err } var key map[string]types.AttributeValue if err := json.Unmarshal(jsonBytes, &key); err != nil { return nil, err } return key, nil }
调整后的分页接口逻辑:
func GetPaginator(tableName string, limit int32, lastKeyStr string) (*dynamodb.ScanPaginator, error) { svc, err := GetClient() if err != nil { logrus.Error(err) return nil, err } exclusiveStartKey, err := DecodeLastKey(lastKeyStr) if err != nil { logrus.Error(err) return nil, err } input := &dynamodb.ScanInput{ TableName: aws.String(tableName), Limit: aws.Int32(limit), ExclusiveStartKey: exclusiveStartKey, } return dynamodb.NewScanPaginator(svc, input), nil }
内容的提问来源于stack exchange,提问作者Zeedinstein
相关产品推荐
相关产品推荐

