@ 细雨适应器/ tidb- server
TiDB 无服务器适配器执行 Drizzle适配器生态系统.
概览
这个 @drizzle-adapter/tidb-serverless 软件包为 Drizzle 适配器接口提供 TiDB 无服务器执行。 虽然你不直接与此软件包互动( 您使用 @drizzle-adapter/core 相反,它为Drizzle适配器生态系统中的TiDB服务器提供了支持.
为什么没有TiDB服务器?
TiDB 无服务器为现代应用提供了独特的优势:
- 分布的 SQL: TiDB 是一个分布式SQL数据库,在保持强烈一致性的同时水平缩放
- MySQL 兼容性: 100% MySQL 兼容,同时提供分布式能力
- 自动缩放: 根据工作量自动计算和储存资源
- 无服务器定价: 只支付每秒计费使用的费用
- HTAP 能力: 实时分析的双重交易和分析处理
- 全球分布: 跨区域部署自动复制数据
- 高可用性: 内置高可用性,自动故障
- 实时分析: 运行复杂的分析查询和交易工作量
完美为:
- 微服务: 独立调整个人服务规模
- 全球应用: 为全球低延迟用户服务
- 实时分析:同时处理交易和分析工作量
- 成本敏感工作量: 只按实际使用支付
- 高成长应用: 从启动到企业的无缝规模
安装
# Install both the core package and the TiDB adapter
pnpm install @drizzle-adapter/core @drizzle-adapter/tidb-serverless
重要:适配器注册
适配器要正确使用 DrizzleAdapterFactory 操作,必须导入它进行自我注册的副作用:
// Import for side effects - adapter will self-register
import '@drizzle-adapter/tidb-serverless';
// Now you can use the factory
import { DrizzleAdapterFactory } from '@drizzle-adapter/core';
使用量
配置
import { DrizzleAdapterFactory, TypeDrizzleDatabaseConfig } from '@drizzle-adapter/core';
const config: TypeDrizzleDatabaseConfig = {
DATABASE_DRIVER: 'tidb-serverless',
DATABASE_URL: 'mysql://user:[email protected]:4000/your-database'
};
const factory = new DrizzleAdapterFactory();
const adapter = factory.create(config);
Schema 定义
const dataTypes = adapter.getDataTypes();
const users = dataTypes.dbTable('users', {
id: dataTypes.dbBigInt('id', { mode: 'number' }).primaryKey().autoincrement(),
name: dataTypes.dbVarChar('name', { length: 255 }).notNull(),
email: dataTypes.dbVarChar('email', { length: 255 }).notNull().unique(),
status: dataTypes.dbEnum('status', ['active', 'inactive']).default('active'),
metadata: dataTypes.dbJson('metadata'),
createdAt: dataTypes.dbTimestamp('created_at').defaultNow()
});
const posts = dataTypes.dbTable('posts', {
id: dataTypes.dbBigInt('id', { mode: 'number' }).primaryKey().autoincrement(),
userId: dataTypes.dbBigInt('user_id', { mode: 'number' })
.references(() => users.id),
title: dataTypes.dbVarChar('title', { length: 255 }).notNull(),
content: dataTypes.dbText('content').notNull(),
published: dataTypes.dbBoolean('published').default(false),
createdAt: dataTypes.dbTimestamp('created_at').defaultNow()
});
基本 CRUD 操作
import { eq, and, or, desc } from 'drizzle-orm';
const connection = await adapter.getConnection();
const client = connection.getClient();
try {
// INSERT
// Single insert with returning
const [newUser] = await client
.insert(users)
.values({
name: 'John Doe',
email: '[email protected]',
metadata: { role: 'user' }
})
.returning();
// Bulk insert
await client
.insert(posts)
.values([
{
userId: newUser.id,
title: 'First Post',
content: 'Hello, world!'
},
{
userId: newUser.id,
title: 'Second Post',
content: 'Another post'
}
]);
// SELECT
// Select all
const allUsers = await client
.select()
.from(users);
// Select with conditions
const activeUsers = await client
.select()
.from(users)
.where(eq(users.status, 'active'));
// Select with multiple conditions
const specificPosts = await client
.select()
.from(posts)
.where(
and(
eq(posts.userId, newUser.id),
eq(posts.published, true)
)
);
// Select with join
const userPosts = await client
.select({
userName: users.name,
postTitle: posts.title,
postContent: posts.content
})
.from(posts)
.leftJoin(users, eq(posts.userId, users.id))
.where(eq(posts.published, true))
.orderBy(desc(posts.createdAt));
// Select with complex conditions
const searchResults = await client
.select()
.from(posts)
.where(
or(
eq(posts.published, true),
eq(posts.userId, newUser.id)
)
)
.orderBy(desc(posts.createdAt))
.limit(10);
// UPDATE
// Update single record
const [updated] = await client
.update(users)
.set({ name: 'John Smith' })
.where(eq(users.id, newUser.id))
.returning();
// Update multiple records
await client
.update(posts)
.set({ published: true })
.where(eq(posts.userId, newUser.id));
// DELETE
// Delete single record
await client
.delete(users)
.where(eq(users.id, newUser.id));
// Delete with conditions
await client
.delete(posts)
.where(
and(
eq(posts.userId, newUser.id),
eq(posts.published, false)
)
);
} finally {
await connection.disconnect();
}
TiDB 特定特性
分布式交易
const orders = dataTypes.dbTable('orders', {
id: dataTypes.dbBigInt('id', { mode: 'number' }).primaryKey().autoincrement(),
userId: dataTypes.dbBigInt('user_id', { mode: 'number' }),
amount: dataTypes.dbDecimal('amount', { precision: 10, scale: 2 }),
status: dataTypes.dbEnum('status', ['pending', 'completed', 'failed']),
createdAt: dataTypes.dbTimestamp('created_at').defaultNow()
});
// TiDB handles distributed transactions automatically
async function createOrder(userId: number, amount: number) {
const connection = await adapter.getConnection();
const client = connection.getClient();
try {
const [order] = await client
.insert(orders)
.values({
userId,
amount,
status: 'pending'
})
.returning();
// Even in a distributed environment, this is ACID compliant
return order;
} finally {
await connection.disconnect();
}
}
实时分析
const analytics = dataTypes.dbTable('analytics', {
id: dataTypes.dbBigInt('id', { mode: 'number' }).primaryKey().autoincrement(),
metric: dataTypes.dbVarChar('metric', { length: 255 }),
value: dataTypes.dbDouble('value'),
dimensions: dataTypes.dbJson('dimensions'),
timestamp: dataTypes.dbTimestamp('timestamp').defaultNow()
});
// TiDB can handle analytical queries alongside transactional workloads
async function getMetricsTrends() {
const client = await adapter.getConnection().getClient();
return client
.select({
metric: analytics.metric,
hourly_avg: sql`AVG(${analytics.value})`,
hour: sql`DATE_FORMAT(${analytics.timestamp}, '%Y-%m-%d %H:00:00')`
})
.from(analytics)
.groupBy(analytics.metric, sql`hour`)
.orderBy(desc(sql`hour`));
}
最佳做法
- 连接管理: 总是尝试/最后使用以确保连接被正确关闭
- 批量操作: 尽可能使用批量插入/更新,以提高性能
- 交易: 利用TiDB的分布式交易能力
- 查询优化: 使用适当的索引和限制结果集
- 处理错误: 对瞬态错误执行正确的再试逻辑
捐款
我们欢迎捐款! 请随意提交拉力请求 对于重大变动,请先开出一个问题来讨论你想要改变什么.
相关软件包
- @ 细雨适应器/ 核心 - 核心接口和类型
- @ 细雨适应器/ mysql- core - 共享 MySQL 功能