表里明明已有数据,调用currval却提示本会话尚未定义。这个函数读取的是当前会话对指定序列最近取得的值,并不是查询全表最大的ID。

为什么有数据也会报错
currval要求当前会话此前对该序列调用过nextval。其他连接插入过数据,不会替当前会话建立这份状态。表中存在记录与当前会话是否用过序列是两回事。显式指定ID的插入也可能没有调用序列。
先确认序列名与物理连接
对串行列或identity列,可执行SELECT pg_get_serial_sequence('public.orders', 'id');核对关联序列,再检查插入和取值是否使用同一个物理数据库会话。连接池把两条SQL分配到不同连接时,后一次currval可能报错或返回该连接更早的值。
事务池模式下不要依赖跨事务保留的序列会话状态。还要区分未定义与权限不足;currval需要该序列的USAGE或SELECT权限。
优先让插入直接返回ID
需要本次插入主键时,可使用INSERT INTO public.orders (note) VALUES ('demo') RETURNING id;,表名和字段须换成实际定义。客户端应直接读取这条语句的结果集,批量插入则读取全部返回行。
RETURNING把生成ID与本次写入关联起来。别用SELECT max(id)取代它,并发写入时最大ID未必属于当前请求。
不要为了消除报错随意推进序列
单独执行nextval会消耗序列值,不能帮你找回另一连接刚插入的行。序列推进不随事务回滚而收回,因此有空洞是正常现象。lastval也依赖当前会话最近使用的序列,触发器使用其他序列时更需谨慎。
不要用setval重置序列来修复currval会话错误。重置可能干扰并发写入,只有明确的序列同步问题才应按维护流程处理。
用连接池真实路径验收
在萤光云或LightNode的测试VPS创建无敏感数据样本,分别用两个连接及应用连接池执行插入,确认每次RETURNING返回的主键与该次写入内容对应。验收覆盖并发和回滚路径,允许序列出现空洞,但不能拿错记录ID。
FAQ
currval会受其他会话插入影响吗? 不会,它返回当前会话取得的序列值。
新连接可直接用currval吗? 未在该会话对指定序列调用nextval时会报错。
RETURNING会额外插入记录吗? 不会,它返回本条写入处理后的数据。
回滚为何不归还序列号? 序列设计允许并发分配,推进不会因回滚收回。
缺少权限与未定义一样吗? 不是,应按错误消息区分,再给最小必要权限。
温馨提示
不要把连续ID当成业务订单数量。上线改用RETURNING时,同时核对驱动结果读取和批量写入映射,避免只取第一行。


