Gel 标准库 sequence 类型:自增序列的声明、推进、重置与并发语义

发布时间:2026/9/23 2:47:27

Gel 标准库 sequence 类型:自增序列的声明、推进、重置与并发语义 Gel 标准库 sequence 类型自增序列的声明、推进、重置与并发语义【免费下载链接】edgedbGel supercharges Postgres with a modern data model, graph queries, Auth AI solutions, and much more.项目地址: https://gitcode.com/gh_mirrors/ed/edgedbstd::sequence是 GelEdgeDB标准库中内置的抽象标量类型用于生成基于int64的自动递增整数序列。本文围绕 docs/reference/stdlib/sequence.rst 展开完整讲解如何用sequence声明自增属性、通过sequence_next()/sequence_reset()推进与重置序列、如何用introspect或运行时查询指定序列以及高并发下序列不回滚、可能产生间隙的事务语义同时结合仓库源码与测试用例剖析其底层基于 PostgreSQLnextval/setval的实现原理。读完本文你将能够在自己的 Gel 模式中安全、高效地设计票号、订单号等自增业务标识。一、认识std::sequenceint64 自增序列std::sequence是一个抽象标量类型abstract scalar type在标准库中定义如下见 edb/lib/std/10-scalars.edgeqlCREATE ABSTRACT SCALAR TYPE std::sequence EXTENDING std::int64;也就是说sequence本质上是int64的扩展任何extending sequence的自定义标量类型都是一个“序列类型”其值由系统按递增顺序自动生成。它天然适合作为自动递增的数值属性的基类型。1.1 声明自增属性在 SDL 模式中你可以通过定义一个扩展sequence的标量类型再把它用作某个对象类型的属性scalar type TicketNo extending sequence; type Ticket { number: TicketNo { constraint exclusive; } }这是官方文档给出的标准用法TicketNo扩展sequenceTicket.number使用TicketNo并加上exclusive约束以保证唯一。仓库测试模式中也大量采用这种写法例如 tests/schemas/dump03_default.esdl 中的scalar type MySeq extending sequence;和scalar type MyPristineSeq extending sequence;以及 tests/schemas/insert.esdl 中的scalar type int_seq8_t extending sequence;。1.2 序列绑定到类型而非属性一个关键语义是序列绑定的是标量类型而不是属性。因此如果多个属性共享同一个序列类型它们会共享同一个计数器。例如如果Order和Invoice两个类型都使用DocNo扩展sequence作为编号属性那么它们产出的编号来自同一个递增序列互相穿插、不重复也不独立。最佳实践如果你需要 N 个互不干扰的计数器就应定义 N 个不同的extending sequence标量类型每个类型对应一条独立的序列。二、sequence_next()推进序列并取值sequence_next(seq: schema::ScalarType) - int64将给定序列推进到下一个值并返回该值。原子性序列推进是原子的每个并发会话和事务都会获得互不相同的序列值不会出现两个会话拿到同一个号。调用方式需要传入一个schema::ScalarType对象通常是introspect的结果。db select sequence_next(introspect MySequence); {11}从源码看sequence_next的实现直接映射到 PostgreSQL 的nextval见 edb/lib/schema.edgeqlSELECT pg_catalog.nextval( pg_catalog.quote_ident(sn.schema) || . || pg_catalog.quote_ident(sn.name) ) FROM ROWS FROM (edgedb_VER.get_user_sequence_backend_name(seq)) AS sn(schema text, name text)其中get_user_sequence_backend_name负责把 Gel 层的序列标量类型解析为后端 PostgreSQL 中实际的 sequence 对象schema 名 序列名nextval是 PostgreSQL 原生的、并发安全的序列推进函数。这意味着 Gel 的序列语义与 PostgreSQL 序列高度一致——包括“不回滚”的行为详见第五节。三、sequence_reset()重置序列sequence_reset有两个重载形式见 edb/lib/schema.edgeqlstd::sequence_reset(seq: schema::ScalarType) - int64 std::sequence_reset(seq: schema::ScalarType, val: int64) - int64两个形式都会返回当前重置后的值。3.1 单参数形式重置到初始状态sequence_reset(seq)将序列重置到初始状态下一次sequence_next将返回序列的第一个值默认从 1 开始db select sequence_reset(introspect MySequence); {1} db select sequence_next(introspect MySequence); {1}其底层实现是从pg_catalog.pg_sequences读取该序列的start_value再以is_called false调用pg_catalog.setval这样下一次nextval就会从起始值重新开始见 edb/lib/schema.edgeql。3.2 双参数形式设置当前值sequence_reset(seq, val)将序列的当前值设置为val下一次sequence_next返回的是你传入值之后的下一个值即val 1除非另有设置db select sequence_reset(introspect MySequence, 22); {22} db select sequence_next(introspect MySequence); {23}底层实现是以is_called true调用pg_catalog.setval即把“已取到的最后一个值”记为val因此下一次取号自然从val 1继续见 edb/lib/schema.edgeql。四、指定序列的最佳实践introspect 与运行时查询无论sequence_next还是sequence_reset都需要传入一个schema::ScalarType对象来指明操作哪条序列。文档专门给出了两种场景下的推荐写法见原文档 docs/reference/stdlib/sequence.rst 中ref_std_specifying_sequence一节。4.1 序列类型编译期已知优先用introspect如果序列类型在写查询时已经确定、不会变化推荐用introspect运算符直接引用类型select sequence_next(introspect MySequenceType); # or select sequence_next(introspect typeof MyObj.seq_prop);两种写法都可行直接introspect序列标量类型本身或者通过typeof从某个属性反推其类型。这样做的意义在于表达式对序列类型的引用会被正确追踪从而保证模式层面的引用完整性referential integrity——编译器能够感知“这条查询依赖了哪个序列类型”避免序列被误删或改名后查询静默失效。仓库测试同样遵循这一风格例如 tests/test_dump03.py 中SELECT sequence_next(INTROSPECT TYPEOF Test.seq) SELECT sequence_next(INTROSPECT MyPristineSeq)4.2 序列类型运行时才确定查询schema::ScalarType如果序列类型必须由查询参数在运行时决定例如用户传入序列名introspect就派不上用场了。此时需要直接从schema::ScalarType集合中按名字查询with SeqType : ( select schema::ScalarType filter .name str$seq_type_name ) select sequence_next(SeqType);这里schema::ScalarType是 Gel 内省introspection体系中所有标量类型的抽象基类$seq_type_name是运行时传入的完整类型名如default::MySequence。这种写法牺牲了一部分编译期引用追踪能力但换来了动态选择序列的灵活性——适用于多租户、多计数器等按需切换序列的场景。五、高并发与事务语义序列不回滚允许出现间隙文档对序列的事务行为给出了明确的警告这也是使用序列时最容易踩坑的地方sequence_next的执行永远不会回滚即使包含它的事务最终被中止abort已经取走的序列值也不会归还。因此生成的序列可能出现间隙gaps——例如事务 A 取走 10、11 后回滚事务 B 接着会取到 1210 和 11 就永久空置。同样sequence_reset的结果在事务回滚时也不会被撤销——重置操作一旦生效即持久化。这一行为与 PostgreSQL 原生序列完全一致nextval/setval属于非事务性操作non-transactional其副作用不随事务提交/回滚而改变。从源码可以确认Gel 的序列函数就是直接透传调用 PostgreSQL 的nextval/setval见 edb/lib/schema.edgeql因此继承了这一语义。5.1 对应用设计的影响不要假设编号连续。如果业务要求“编号必须是连续的”序列方案并不合适应改用应用层加锁计数或事后补号等方案。序列值适合做标识、不适合做严格顺序依据。若需要“编号即时间顺序”在高并发 回滚场景下序列值无法保证与提交顺序严格一致。间隙是特性而非缺陷。间隙换来的是无锁竞争的高并发性能——nextval通过 PostgreSQL 内部机制原子递增多个会话互不阻塞。六、权限要求sequence_reset 需要 DDL 权限从权限模型看sequence_next与sequence_reset的权限要求并不相同。在 edb/lib/sys.edgeql 中可以看到标准库对两个sequence_reset重载都额外声明了ALTER FUNCTION std::sequence_reset(...) { SET required_permissions : sys::perm::ddl; };也就是说调用sequence_reset需要 DDL 级别的权限因为它会修改序列的状态而sequence_next没有这样的额外限制普通数据操作即可调用。在权限敏感的应用中应把重置序列的能力限制在管理员/迁移类角色上普通用户只允许取号。七、应用场景小结场景推荐做法自增业务编号票号、订单号、流水号定义scalar type XxxNo extending sequence;属性加constraint exclusive多个实体共享一个计数器多个属性使用同一个序列类型注意编号会交叉多个独立计数器每个计数器单独定义一个extending sequence类型编译期已知序列类型sequence_next(introspect MySeqType)或introspect typeof Obj.prop运行时动态选择序列select schema::ScalarType filter .name str$name后传入函数重置到起始值sequence_reset(seq)下次取号返回第一个值从指定值继续sequence_reset(seq, 22)下次取号返回 23需要严格无间隙编号序列方案不适用需自行实现补号逻辑八、总结std::sequence为 Gel 提供了简洁而强大的自增序列能力通过extending sequence声明序列类型并绑定属性用sequence_next原子取号、用sequence_reset重置状态配合introspect保证引用完整性且底层由 PostgreSQL 的nextval/setval提供并发安全与持久化保证。需要始终牢记的是其“不回滚、有间隙”的事务语义以及sequence_reset所需的 DDL 权限——理解了这些边界你就能在设计高并发业务标识时做出正确取舍。进一步阅读可在 docs/reference/datamodel/properties.rst 了解属性与约束constraint exclusive的完整语义在 docs/reference/stdlib/introspection.rst 所在的 docs/reference/stdlib 目录下查看schema::ScalarType等内省类型的说明或在 edb/lib/std/10-scalars.edgeql 与 edb/lib/schema.edgeql 中直接阅读序列的声明与实现源码。【免费下载链接】edgedbGel supercharges Postgres with a modern data model, graph queries, Auth AI solutions, and much more.项目地址: https://gitcode.com/gh_mirrors/ed/edgedb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/23 4:22:31

SpringBoot+Vue+Hive旅游数据分析系统架构与实现全解析

做了几个大数据方向的Web项目后,我越来越觉得“数据平台”这类系统最大的难点不在技术有多新,而在于“数据怎么取、指标怎么算、结果怎么展示”这一整条链路能不能串起来。这次我整理的这个基于SpringBootVue的Hive旅游数据分析系统,就是一个…

2026/9/23 4:22:31

快慢思考分层:Claude Code+Jev+/loop让AI Agent成本降90%

最近在给团队搭内部AI Agent平台时,一个很现实的问题把我逼到了墙角:什么任务都塞给旗舰模型,结果是账单每天几百美元地涨,而且很多活根本不需要那么强的推理。后来我把整个架构改成“Claude Code Jev /loop”的分层循环方案&am…

2026/9/23 4:22:31

基于大模型AI的芯片电子束晶圆检测系统平台设计与实践

做半导体工艺或者设备这一行的朋友,应该对“晶圆检测”这四个字不陌生。但今天聊的这套东西,不是常规的光学检测机台,而是把大模型和人工智能直接塞进电子束晶圆检测平台里做核心引擎。这个方向在行业里属于既有硬件门槛、又有软件深度的交叉…

2026/9/22 10:02:42

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/22 9:07:39

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/23 0:01:54

3个实战技巧搞定形式英语:从看教程到跑通性能优化

3个实战技巧搞定形式英语:从看教程到跑通性能优化 看了一堆教程还是不会写项目?别慌,这种“眼高手低”的困境在开发者圈子里太常见了。很多人以为卡点在语法,其实真正拦路虎是缺乏将知识点串联成完整链路的能力。今天咱们不聊虚的,直接拿【形式英语】这…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码