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

Spring Data Cassandra传入CassandraPageRequest分页时paging state无效报错

问题根因

你代码有三个核心问题直接导致分页状态报错:

  • 反序列化十六进制字符串为ByteBuffer后未调用flip()重置指针
    你把所有字节写入ByteBuffer后,buffer的position指针处于写入的末尾位置,Cassandra读取分页状态时会从当前position开始读,读到的是空内容,自然抛出无效分页状态错误。
  • 序列化时修改了原ByteBuffer的指针位置
    你写的toHexString方法直接调用原ByteBuffer的get()方法,会移动原buffer的position指针,导致原分页状态对象直接失效。
  • 分页查询逻辑错误
    你第一次查询拿到分页结果后,又重复调用了一次findAll查询下一页,导致返回给前端的分页状态和实际返回的内容不匹配,下次请求用这个状态自然报错。
修复方案

1. 修正序列化方法,操作副本不修改原ByteBuffer

public static String toHexString(ByteBuffer buffer) {
    // 先复制只读副本,操作副本不影响原buffer的指针位置
    ByteBuffer copy = buffer.asReadOnlyBuffer();
    final StringBuilder r = new StringBuilder(copy.remaining() * 2);
    while (copy.hasRemaining()) {
        final byte b = copy.get();
        r.append(HEX_CODE[(b >> 4) & 0xF]);
        r.append(HEX_CODE[(b & 0xF)]);
    }
    return r.toString();
}

2. 修正反序列化逻辑,写入完成后重置指针

map(pageState ->{
    int len = pageState.length();
    ByteBuffer bytes = ByteBuffer.allocate(len / 2);
    for (int i = 0; i < len; i += 2) {
        bytes.put((byte) ((Character.digit(pageState.charAt(i), 16) << 4)
                         + Character.digit(pageState.charAt(i+1), 16)));
     }
    // 重置position到0,后续读取可以拿到所有写入的字节
    bytes.flip();
    return CassandraPageRequest.of(pageRequest,bytes);
})

3. 修正分页查询逻辑,删除多余的二次查询

@Override
public SlicedResult<UserFeed> getUserFeed(String userId, Optional<String> pagingState) {
    final PageRequest pageRequest =  PageRequest.of(0, constants.PAGE_SIZE);
    CassandraPageRequest cassandraPageRequest =
            pagingState.
                    map(pageState ->{
                                int len = pageState.length();
                                ByteBuffer bytes = ByteBuffer.allocate(len / 2);
                                for (int i = 0; i < len; i += 2) {
                                    bytes.put((byte) ((Character.digit(pageState.charAt(i), 16) << 4)
                                                     + Character.digit(pageState.charAt(i+1), 16)));
                                 }
                                bytes.flip();
                                return CassandraPageRequest.of(pageRequest,bytes);
                        }
                    )
                    .orElse(CassandraPageRequest.first(constants.PAGE_SIZE));
    Slice<UserFeed> userFeedSlice = feedRepository.findAll(cassandraPageRequest);
    CassandraPageRequest nextPageable = ((CassandraPageRequest)userFeedSlice.getPageable());
    ByteBuffer nextPagingState = nextPageable.getPagingState();
    String nextPageStateString =  nextPagingState == null ? null : toHexString(nextPagingState);
    // 删掉多余的第二次findAll调用
    return SlicedResult.<UserFeed>builder().pageState(nextPageStateString).content(userFeedSlice.getContent())
            .build();
}
其他更稳妥的序列化实现方式

你可以直接用Base64编码替代手动实现十六进制转换,出错概率更低:

import java.util.Base64;

// 序列化逻辑
String nextPageStateString = nextPagingState == null ? null : Base64.getUrlEncoder().encodeToString(nextPagingState.array());

// 反序列化逻辑
byte[] bytes = Base64.getUrlDecoder().decode(pageState);
ByteBuffer buffer = ByteBuffer.wrap(bytes);

你也可以直接用Spring Data Cassandra自带的工具类处理分页状态,避免手动操作ByteBuffer出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 14:45:01