关于 drizzle
drizzle 是面向数据库应用开发者的 TypeScript 优先 ORM 技能,涵盖类型安全的架构、类 SQL 查询、事务和迁移流程,支持 PostgreSQL、MySQL 与 SQLite。
主要功能
- 01类型安全的 TypeScript 架构
- 02类 SQL 查询与联接
- 03支持回滚的事务
- 04生成并应用迁移
- 05支持 PostgreSQL、MySQL 和 SQLite
适用场景
- 01设计关系型数据库架构
- 02编写筛选与分页查询
- 03安全执行多步更新
- 04管理数据库架构变更
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bobmatnyc/ claude-mpm-skills --skill drizzle-orm安装后在 Claude Code 中输入/drizzle-orm确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
metadata.jsonreferences/advanced-schemas.mdperformance.mdquery-patterns.mdvs-prisma.md详细介绍
Drizzle ORM
现代化、以 TypeScript 为先的 ORM,零依赖,具备编译时类型安全性,并采用类似 SQL 的语法。针对边缘运行时和无服务器环境进行了优化。
快速开始
安装
# Core ORM
npm install drizzle-orm
# Database driver (choose one)
npm install pg # PostgreSQL
npm install mysql2 # MySQL
npm install better-sqlite3 # SQLite
# Drizzle Kit (migrations)
npm install -D drizzle-kit
基本设置
// db/schema.ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: text('email').notNull().unique(),
name: text('name').notNull(),
createdAt: timestamp('created_at').defaultNow(),
});
// db/client.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import * as schema from './schema';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export const db = drizzle(pool, { schema });
第一个查询
import { db } from './db/client';
import { users } from './db/schema';
import { eq } from 'drizzle-orm';
// Insert
const newUser = await db.insert(users).values({
email: '[email protected]',
name: 'John Doe',
}).returning();
// Select
const allUsers = await db.select().from(users);
// Where
const user = await db.select().from(users).where(eq(users.id, 1));
// Update
await db.update(users).set({ name: 'Jane Doe' }).where(eq(users.id, 1));
// Delete
await db.delete(users).where(eq(users.id, 1));
Schema 定义
列类型参考
| PostgreSQL | MySQL | SQLite | TypeScript |
|---|---|---|---|
serial() | serial() | integer() | number |
text() | text() | text() | string |
integer() | int() | integer() | number |
boolean() | boolean() | integer() | boolean |
timestamp() | datetime() | integer() | Date |
json() | json() | text() | unknown |
uuid() | varchar(36) | text() | string |
常见 Schema 模式
import { pgTable, serial, text, varchar, integer, boolean, timestamp, json, unique } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: varchar('email', { length: 255 }).notNull().unique(),
passwordHash: varchar('password_hash', { length: 255 }).notNull(),
role: text('role', { enum: ['admin', 'user', 'guest'] }).default('user'),
metadata: json('metadata').$type<{ theme: string; locale: string }>(),
isActive: boolean('is_active').default(true),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
}, (table) => ({
emailIdx: unique('email_unique_idx').on(table.email),
}));
// Infer TypeScript types
type User = typeof users.$inferSelect;
type NewUser = typeof users.$inferInsert;
关系
一对多
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const authors = pgTable('authors', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
});
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
authorId: integer('author_id').notNull().references(() => authors.id),
});
export const authorsRelations = relations(authors, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(authors, {
fields: [posts.authorId],
references: [authors.id],
}),
}));
// Query with relations
const authorsWithPosts = await db.query.authors.findMany({
with: { posts: true },
});
多对多
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
});
export const groups = pgTable('groups', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
});
export const usersToGroups = pgTable('users_to_groups', {
userId: integer('user_id').notNull().references(() => users.id),
groupId: integer('group_id').notNull().references(() => groups.id),
}, (table) => ({
pk: primaryKey({ columns: [table.userId, table.groupId] }),
}));
export const usersRelations = relations(users, ({ many }) => ({
groups: many(usersToGroups),
}));
export const groupsRelations = relations(groups, ({ many }) => ({
users: many(usersToGroups),
}));
export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
user: one(users, { fields: [usersToGroups.userId], references: [users.id] }),
group: one(groups, { fields: [usersToGroups.groupId], references: [groups.id] }),
}));
查询
筛选
import { eq, ne, gt, gte, lt, lte, like, ilike, inArray, isNull, isNotNull, and, or, between } from 'drizzle-orm';
// Equality
await db.select().from(users).where(eq(users.email, '[email protected]'));
// Comparison
await db.select().from(users).where(gt(users.id, 10));
// Pattern matching
await db.select().from(users).where(like(users.name, '%John%'));
// Multiple conditions
await db.select().from(users).where(
and(
eq(users.role, 'admin'),
gt(users.createdAt, new Date('2024-01-01'))
)
);
// IN clause
await db.select().from(users).where(inArray(users.id, [1, 2, 3]));
// NULL checks
await db.select().from(users).where(isNull(users.deletedAt));
联接
import { eq } from 'drizzle-orm';
// Inner join
const result = await db
.select({
user: users,
post: posts,
})
.from(users)
.innerJoin(posts, eq(users.id, posts.authorId));
// Left join
const result = await db
.select({
user: users,
post: posts,
})
.from(users)
.leftJoin(posts, eq(users.id, posts.authorId));
// Multiple joins with aggregation
import { count, sql } from 'drizzle-orm';
const result = await db
.select({
authorName: authors.name,
postCount: count(posts.id),
})
.from(authors)
.leftJoin(posts, eq(authors.id, posts.authorId))
.groupBy(authors.id);
分页与排序
import { desc, asc } from 'drizzle-orm';
// Order by
await db.select().from(users).orderBy(desc(users.createdAt));
// Limit & offset
await db.select().from(users).limit(10).offset(20);
// Pagination helper
function paginate(page: number, pageSize: number = 10) {
return db.select().from(users)
.limit(pageSize)
.offset(page * pageSize);
}
事务
// Auto-rollback on error
await db.transaction(async (tx) => {
await tx.insert(users).values({ email: '[email protected]', name: 'John' });
await tx.insert(posts).values({ title: 'First Post', authorId: 1 });
// If any query fails, entire transaction rolls back
});
// Manual control
const tx = db.transaction(async (tx) => {
const user = await tx.insert(users).values({ ... }).returning();
if (!user) {
tx.rollback();
return;
}
await tx.insert(posts).values({ authorId: user.id });
});
迁移
Drizzle Kit 配置
// drizzle.config.ts
import type { Config } from 'drizzle-kit';
export default {
schema: './db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
} satisfies Config;
迁移工作流
# Generate migration
npx drizzle-kit generate
# View SQL
cat drizzle/0000_migration.sql
# Apply migration
npx drizzle-kit migrate
# Introspect existing database
npx drizzle-kit introspect
# Drizzle Studio (database GUI)
npx drizzle-kit studio
迁移示例
-- drizzle/0000_initial.sql
CREATE TABLE IF NOT EXISTS "users" (
"id" serial PRIMARY KEY NOT NULL,
"email" varchar(255) NOT NULL,
"name" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
CONSTRAINT "users_email_unique" UNIQUE("email")
);
导航
详细参考
-
🏗️ 高级 Schema - 自定义类型、复合键、索引、约束、多租户模式。设计复杂数据库 Schema 时加载。
-
🔍 查询模式 - 子查询、CTE、原始 SQL、预处理语句、批量操作。优化查询或处理复杂筛选时加载。
-
⚡ 性能 - 连接池、查询优化、避免 N+1、预处理语句、边缘运行时集成。扩展或优化数据库性能时加载。
-
🔄 与 Prisma 对比 - 功能对比、迁移指南、何时选择 Drizzle 而非 Prisma。评估 ORM 或从 Prisma 迁移时加载。
注意事项
遇到以下情况时请停下来重新考虑:
- 对 JSON 列使用
any或unknown,但未进行类型标注 - 未使用
sql模板构建原始 SQL 字符串(存在 SQL 注入风险) - 多步骤数据修改未使用事务
- 在生产查询中不分页地获取所有行
- 外键或频繁查询的列缺少索引
- 对大型表使用
select()时未指定列
相较于 Prisma 的性能优势
| 指标 | Drizzle | Prisma |
|---|---|---|
| 包体积 | ~35KB | ~230KB |
| 冷启动 | ~10ms | ~250ms |
| 查询速度 | 基准 | 慢约 2-3 倍 |
| 内存 | ~10MB | ~50MB |
| 类型生成 | 运行时推断 | 构建时生成 |
集成
- typescript-core:使用
satisfies进行类型安全的 Schema 推断 - nextjs-core:集成 Server Actions、Route Handlers、Middleware
- 数据库迁移:安全的 Schema 演进模式
相关技能
使用 Drizzle 时,以下技能可改进你的工作流:
- prisma:替代 ORM 对比:Drizzle 与 Prisma 的权衡
- typescript:用于类型安全查询的高级 TypeScript 模式
- nextjs:在 Next.js Server Actions 和 API 路由中使用 Drizzle
- sqlalchemy:供学习 Drizzle 的 Python 开发者参考的 SQLAlchemy 模式
[如果这些技能已部署在你的资源包中,可查阅完整文档]
评论
支持 Markdown