正文
解构 pgx 的魔法
那么,pgx 代码究竟施展了什么样的魔法,让 postgres extension 的撰写如此简单?
答案是 Rust 自身的诸多特性:内存和并发安全性,宏支持,以及和 C 的 ABI 的兼容。这些特性共同造就了 pgx 如此优雅的使用体验:
-
使用
pg_module_magic!()
来处理 extension 的脚手架代码。这个宏的背后是一大坨脚手架代码来设置 extension 的上下文。
-
使用
#[pg_extern]
来封装 Rust 函数,使其接口符合 postgres extension 的 C ABI,以及处理 Rust 数据结构和 postgres 内部数据结构的转换。
-
#[pg_extern]
和
default!
宏甚至可以帮助 pgx 工具链生成相关的 SQL 语句,这样当打包一个完整的 extension 时,你可以省却撰写这些 SQL 语句的痛苦。
不要忘了,Rust 还有无与伦比的正确性的保证。正如我曾经介绍过的,可以用 Rust 扩展 elixir 能力的 rustler 项目一样,你的 pgx 代码,只要编译通过,便(几乎)没有内存安全和并发安全问题;并且,如果在你的 extension 中,抛出致命异常(panic),postgres server 不会崩溃,只是执行这个操作的 transaction 被回滚而已。
这些能力,其它编程语言只具备一部分:它们或者效率不高,或者表现力不强,或者无法保证程序的正确性,或者用繁文缛节恶心死你(我发誓不是在说 java):
真的有必要写自己的 postgres extension 呢?
很多时候,我们不去做一件事,或者想不到做这样的事情有什么意义的时候,往往可能因为我们没有能力去做。当我们被赋能的时候,无穷的想象力就会同时喷薄而出。
更好的 ID 系统?
做数据库设计的时候,我们最头疼的问题是如何设计一个有意义、高性能且保证一定随机性的 ID。自增 ID 缺乏随机性,且会暴露数据细节(黑客可以通过 id 的规律爬到大量数据);UUID4 具备足够随机性,但无法排序。如果我想把 mongodb 的 ObjectId 或者 uuid7(可排序)引入 postgres 可以么?如果我想把应用程序内部定义的某个 ID 结构映射到 postgres 可以么?