ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MikroORM 与 CockroachDB 集成实战指南:基于 PostgreSQL 驱动的配置、主键策略与兼容性边界

MikroORM 与 CockroachDB 集成实战指南:基于 PostgreSQL 驱动的配置、主键策略与兼容性边界 后端【免费下载链接】mikro-ormTypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.项目地址https://gitcode.com/gh_mirrors/mi/mikro-orm点击查看免费下载本文是 MikroORM 官方使用指南的深度展开讲解如何通过mikro-orm/postgresql驱动接入 CockroachDB一个 PostgreSQL wire 兼容的分布式数据库。你将掌握最小化配置、CockroachDB Cloud SSL 连接、UUID 与BigIntType两种主键策略、Schema 生成器的正确用法以及经过仓库测试验证的能力清单与已知限制从而在生产环境中规避int8精度、TRUNCATE等典型陷阱。CockroachDB 兼容性基础为什么不需要单独安装驱动包MikroORM 对 CockroachDB 的支持建立在「PostgreSQL wire 兼容」这一前提之上CockroachDB 对外提供与 PostgreSQL 一致的网络协议与 SQL 方言因此 MikroORM 无需为它维护独立驱动包直接复用 PostgreSQL 驱动栈即可。从源码结构看这条链路是完整打通的PostgreSqlDriver 继承自AbstractSqlDriver并注册了PostgreSqlPlatform、PostgreSqlConnection与[kysely, pg]两个原生客户端选项PostgreSqlConnection 基于pg的Pool实现连接池并支持 kysely dialect 与游标查询PostgreSqlPlatform 继承自BasePostgreSqlPlatform负责类型声明、序列化与方言差异的收口。仓库根目录的 docker-compose.yml 中也内置了 CockroachDB 服务镜像cockroachdb/cockroach:latest-v24.3以start-single-node --insecure启动映射端口26257与8080可直接用于本地开发与复现本文示例。CockroachDB 官方还建议使用 UUID 主键以获得跨节点的均匀数据分布这会在后文的主键策略中详细展开。安装安装 PostgreSQL 驱动即可不需要任何单独的 CockroachDB 包npm install mikro-orm/core mikro-orm/postgresqlmikro-orm/core提供实体、EntityManager 与 Schema 生成器等核心能力mikro-orm/postgresql提供驱动与方言实现。若同时使用 CLI 或迁移功能可额外安装mikro-orm/cli、mikro-orm/migrations等配套包。配置基础连接与默认端口差异一个最小的 CockroachDB 配置如下import { defineConfig } from mikro-orm/postgresql; export default defineConfig({ entities: [./dist/entities], entitiesTs: [./src/entities], dbName: my_database, host: localhost, port: 26257, user: root, password: , });需要特别记住的关键差异是CockroachDB 默认端口为26257而非 PostgreSQL 的5432。本地单节点insecure 模式默认用户为root且密码为空与 docker-compose.yml 中start-single-node --insecure的启动方式对应。测试套件 tests/features/cockroachdb.test.ts 中的初始化代码与此一致orm await MikroORM.init({ entities: allEntities, dbName: mikro_orm_crdb_${(Math.random() 1).toString(36).substring(7)}, port: 26257, user: root, password: , logger: i i, extensions: [Migrator, SeedManager, EntityGenerator], });注意测试同时挂载了Migrator、SeedManager、EntityGenerator三个扩展表明迁移、种子与实体生成在 CockroachDB 上均可用。CockroachDB CloudSSL配置CockroachDB Cloud 强制要求 SSL 连接。CA 证书通过driverOptions传入该选项会直接映射为pg.Pool的连接选项参见 PostgreSqlConnection 中对pgPoolConfig的使用import { defineConfig } from mikro-orm/postgresql; import { readFileSync } from node:fs; export default defineConfig({ dbName: my_database, host: your-cluster.cockroachlabs.cloud, port: 26257, user: your-user, password: your-password, driverOptions: { ssl: { ca: readFileSync(./path/to/ca-cert.crt, utf8), }, }, });driverOptions透传的灵活性意味着你还可以按需传入pg支持的其他选项例如ssl: { rejectUnauthorized: false }仅限调试环境或自定义连接超时等。生产环境务必校验 CA 证书。主键策略绕开 int8 精度陷阱CockroachDB 的serial类型并非 PostgreSQL 意义上的「int4 sequence」而是基于unique_rowid()生成的64 位整数int8。这类值极易超过 JavaScriptNumber.MAX_SAFE_INTEGER2^53 - 1而pg驱动会把超出安全范围的整数以字符串返回因此实体主键类型必须与这一行为匹配。从源码看这一行为在方言层有明确支撑在 BasePostgreSqlPlatform 中getIntegerTypeDeclarationSQL在autoincrement时返回serial、getBigIntTypeDeclarationSQL返回bigserial/bigint而isBigIntProperty会把列类型为bigserial或int8的属性判定为 bigint 属性escape()在写入时也会把bigint转为字符串。方案一UUID 主键推荐CockroachDB 官方推荐 UUID 主键serial/自增键会导致写入热点所有写入集中在单个 range而 UUID 可将写入均匀分布到各节点。MikroORM 的defineEntity与装饰器两种风格均支持const Author defineEntity({ name: Author, properties: { id: p.uuid().primary(), name: p.string(), }, });Entity() class Author { PrimaryKey({ type: uuid }) id: string v4(); Property() name!: string; }仓库的 CockroachDB 测试实体统一采用了 UUID 主键并额外用defaultRaw(gen_random_uuid())让数据库侧生成 UUID例如 tests/features/cockroachdb.test.ts 中的CrdbAuthorconst CrdbAuthor defineEntity({ name: CrdbAuthor, tableName: crdb_author, properties: { id: p.uuid().primary().defaultRaw(gen_random_uuid()), name: p.string(), // ... }, });gen_random_uuid()是 CockroachDB 内置的 UUID 生成函数defaultRaw会把原始 SQL 作为列默认值从而兼顾「应用侧不必预生成 ID」与「数据库侧均匀分布」两个诉求。方案二serial主键 BigIntType如果确实需要自增风格的主键用BigIntType把serial值映射为string或原生bigintconst Author defineEntity({ name: Author, properties: { id: p.bigint(string).primary(), name: p.string(), }, });或映射为原生bigintconst Author defineEntity({ name: Author, properties: { id: p.bigint().primary(), name: p.string(), }, });装饰器写法对应为Entity() class Author { PrimaryKey({ type: new BigIntType(string) }) id!: string; }或原生bigintEntity() class Author { PrimaryKey() id!: bigint; }BigIntType的实现位于 packages/core/src/types/BigIntType.ts它有三种模式bigint默认数据库字符串值转原生bigint、string保持字符串、number仅对不超过Number.MAX_SAFE_INTEGER的值安全。写入时统一 value转为字符串发送给pgfromJSON中还对number模式做了安全整数校验防止游标/序列化过程静默舍入。唯一不可行的是PrimaryKey() id!: number/p.integer().primary()—— CockroachDB 的serial值对 JavaScriptnumber类型来说太大了会导致精度丢失。这是本方案最需要牢记的红线。整数列的特别处理CockroachDB 在内部会把所有整数类型int2、int4、int8统一映射为 64 位整数。pg驱动同样只对超过Number.MAX_SAFE_INTEGER的值返回字符串因此对age、count这类常规业务整数列取值落在安全范围内直接用number类型即可对可能超限的列应改用bigint或string。方言层的normalizeColumnType见 BasePostgreSqlPlatform会把int/int4/integer/serial归一化为int、把bigint/int8/bigserial归一化为bigint保持类型声明的一致性。测试中也验证了这一行为CrdbAuthor.age声明为p.integer()但读取时断言Number(found.age) 42见 tests/features/cockroachdb.test.ts因为数据库返回的可能是字符串形式的整数。Schema 生成器orm.schema在 CockroachDB 上完整可用create()、update()、drop()均可按常规方式调用await orm.schema.create(); await orm.schema.update(); await orm.schema.drop();清空数据库TRUNCATE ... RESTART IDENTITY的替代方案CockroachDB不支持PostgreSQL 的TRUNCATE ... RESTART IDENTITY。默认情况下orm.schema.clear()会生成truncate语句因此在 CockroachDB 上必须显式传入truncate: false回退到按依赖顺序的DELETE语句await orm.schema.clear({ truncate: false });其底层实现值得展开在 packages/sql/src/schema/SqlSchemaGenerator.ts 的clear()中默认走 truncate 分支当options?.truncate false时转调父类实现 AbstractSchemaGenerator.clear()后者遍历元数据并按依赖顺序逆序调用driver.nativeDelete—— 即先删「被引用方」、后删「引用方」从而在无外键检查的情况下安全清空全部数据最后默认清空 Identity Map。测试套件在beforeEach阶段正是这样清库的beforeEach(async () { // CockroachDB doesnt support truncate ... restart identity, so we use // truncate: false to fall back to ordered delete from statements. await orm.schema.clear({ truncate: false }); });Schema 差异Diffing由于 CockroachDB 的 catalog系统目录实现与 PostgreSQL 存在差异orm.schema.getUpdateSchemaSQL()的 introspection 结果可能报告一些「小差异」。在应用update之前务必人工审查生成的 SQL确认这些 diff 是真实的结构变更而非 catalog 层面的表象差异。测试中对生成 SQL 的可用性做了基本验证getUpdateSchemaSQL({ wrap: false })与getCreateSchemaSQL({ wrap: false })均返回非空字符串。已通过测试验证的功能清单官方指南列出以下功能已针对 CockroachDB 测试通过且仓库的 tests/features/cockroachdb.test.ts 逐项提供了可复现的断言功能对应测试用例节选CRUD增删改查create and read entity、update entity、delete entity关系ManyToOne / OneToMany / ManyToMany / OneToOnecreate author with book and relations、many-to-many relation、one-to-one relation with cascade自引用关系self-referencing relationsCrdbAuthor.favouriteAuthor自引用 deleteRule(set null)Populate 提示与加载策略SELECT_IN / JOINEDjoined loading strategystrategy: LoadStrategy.JOINED一次 populate author、publisher、tags 三层QueryBuilder 条件、排序与分页QueryBuilder with conditions and ordering$gte、orderByfindAndCount的 limit/offsetpagination with findAndCount10 条数据、limit 3、offset 2、按名排序事务与事务回滚transactions、transaction rollback回滚后断言数据不存在批量插入batch insert一次 flush 10 条Upsertem.upsert()upsert同 email 二次 upsert 更新而非新增JSONB 列JSON operations嵌套对象存取数组列如text[]array column operationsidentities: [id1, id2, id3]UUID 主键所有测试实体Serial 主键配合BigIntType或bigint见主键策略章节Schema 生成器create/update/dropschema generator - getUpdateSchemaSQL、schema generator - getCreateSchemaSQL迁移测试初始化挂载了Migrator扩展测试还额外覆盖了两类文档未单独列出的能力可作为深度佐证乐观锁CrdbFooBar.version声明为p.datetime().version().columnType(timestamptz(0))测试通过等待 1100ms 验证版本戳变化复合主键CrdbFooParam以两个 ManyToOne 字段bar、baz组成复合主键配合updateRule(cascade)完成读写。此外仓库变更记录还提到过一个针对性修复CockroachDB 可能不需要unmarshallArray对数组的再处理见 packages/postgresql/CHANGELOG.md此类小差异均已在驱动层收敛。已知限制一览功能状态说明serial/bigserial主键改用BigIntType或 UUIDCockroachDB 的unique_rowid()返回int8number类型不可用整数类型全部映射为int8小值可用number大值需bigint或stringTRUNCATE ... RESTART IDENTITY不支持改用orm.schema.clear({ truncate: false })polygon、line、path几何类型不支持CockroachDB 不支持 PostgreSQL 几何类型全文检索tsvector不支持CockroachDB 提供自己的全文检索实现MikroORM 的FullTextType依赖 PostgreSQL 的tsvector/GIN 索引能力原生 PostgreSQL 枚举受限建议改用 check 约束表达枚举语义物化视图不支持CockroachDB 不支持CREATE MATERIALIZED VIEW可延迟约束deferrable constraints不支持CockroachDB 不支持INITIALLY DEFERRED需要注意的是方言层 BasePostgreSqlPlatform 中supportsNativeEnums()、supportsMaterializedViews()等方法返回true这是为 PostgreSQL 本体设计的在 CockroachDB 上使用这些能力时必须以上表限制为准例如枚举改用 check 约束、避免物化视图与全文索引。完整示例Author / Book 级联写入与查询下面给出一个可直接运行的端到端示例。它演示了实体定义、ORM 初始化、Schema 生成、级联写入与 populate 查询的完整链路。使用defineEntity无装饰器风格const Author defineEntity({ name: Author, properties: { id: p.uuid().primary(), name: p.string(), email: p.string(), books: () p.oneToMany(Book).mappedBy(author), }, }); const Book defineEntity({ name: Book, properties: { id: p.uuid().primary(), title: p.string(), author: () p.manyToOne(Author), }, }); const orm await MikroORM.init({ entities: [Author, Book], dbName: my_database, host: localhost, port: 26257, user: root, password: , }); await orm.schema.update(); const em orm.em.fork(); const author em.create(Author, { name: John, email: johnexample.com }); em.create(Book, { title: My Book, author }); await em.flush(); const books await em.find(Book, {}, { populate: [author] }); console.log(books[0].author.name); // John await orm.close();使用装饰器风格Entity() class Author { PrimaryKey({ type: uuid }) id: string v4(); Property() name!: string; Property() email!: string; OneToMany(() Book, book book.author) books new CollectionBook(this); } Entity() class Book { PrimaryKey({ type: uuid }) id: string v4(); Property() title!: string; ManyToOne(() Author) author!: Author; } const orm await MikroORM.init({ entities: [Author, Book], driver: PostgreSqlDriver, metadataProvider: ReflectMetadataProvider, dbName: my_database, host: localhost, port: 26257, user: root, password: , }); await orm.schema.update(); const em orm.em.fork(); const author em.create(Author, { name: John, email: johnexample.com }); em.create(Book, { title: My Book, author }); await em.flush(); const books await em.find(Book, {}, { populate: [author] }); console.log(books[0].author.name); // John await orm.close();两个版本的运行语义一致em.create建立对象图后一次flush即可按依赖顺序完成 Author 与 Book 的级联写入批量插入由 Unit of Work 自动编排随后的find配合populate: [author]触发关联加载从而直接访问books[0].author.name。该链路与 tests/features/cockroachdb.test.ts 中create author with book and relations的断言完全对应。小结在 MikroORM 中使用 CockroachDB 的关键决策点可以概括为三句话驱动沿用mikro-orm/postgresql端口从5432换成26257主键优先 UUID必须用自增则选BigIntType/bigint而绝不选number清库一律orm.schema.clear({ truncate: false })。其余绝大多数能力——CRUD、四种关系、加载策略、QueryBuilder、事务、批量插入、upsert、JSON/数组列、Schema 生成与迁移——都可开箱即用限制边界集中在上文的已知限制表中。赞分享后端【免费下载链接】mikro-ormTypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.项目地址https://gitcode.com/gh_mirrors/mi/mikro-orm点击查看免费下载相关推荐MikroORM 与 CockroachDB 集成指南配置、主键策略与兼容性要点MikroORM 与 CockroachDB 集成指南配置、主键策略与兼容性要点 MikroORM 通过 mikro orm/postgresql 驱动原生后端scrcpy 安卓投屏免Root延迟35~70msscrcpy 安卓投屏免Root延迟35~70ms scrcpy 是一款免费开源的安卓投屏工具通过手机自带的 ADB 调试通道把 Android 设备的音视频NullClaw 贡献指南从工具链校验到合入 PR 的完整开发流程NullClaw 贡献指南从工具链校验到合入 PR 的完整开发流程 本篇技术指南以仓库根目录的 CONTRIBUTING.md https://link.gi人工智能AI Agent大模型自主智能体工具调用RAGAgent 记忆MCP ClientsAgent 沙箱多智能体语音上一篇【亲测免费】 imageio-ffmpeg 安装与使用指南下一篇Carbon 开源项目使用教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表