找回密码
 立即注册
首页 业界区 业界 Node.js 主流ORM框架动态分表方案大盘点

Node.js 主流ORM框架动态分表方案大盘点

戎玉珂 前天 15:33
针对高并发、数据量大的场景,通常会考虑采用分库分表进行优化。在这篇文章,我们重点盘点一下Node.js主流ORM框架的动态分表方案:
分表规则

比如我们需要对订单表进行分表操作。可以根据实际业务需求设计分表规则,在这里,我们根据顾客Id取模动态生成表名。比如,拆分为16张表,顾客Id为129,对应的表名如下:
  1. const tableName = `Order_${129 % 16}`;  // Order_1
复制代码
TypeORM

在TypeORM中可以按照如下方式设置动态表名:
  1. // 获取repository
  2. const repositoryOrder = dataSource.createQueryBuilder().connection.getRepository(EntityOrder);
  3. // 设置动态表名
  4. const userId = 129;
  5. const tableName = `Order_${userId % 16}`;
  6. repositoryOrder.metadata.tablePath = tableName;
  7. // 查询订单
  8. const orders = await repositoryOrder.find();
复制代码
Drizzle ORM

schema.ts
  1. const orderFactory = userId => pgTable(
  2.   `Order_${userId % 16}`,
  3.   {
  4.     id: serial('id').primaryKey(),  
  5.     name: text('name').notNull(),
  6.   },
  7. );
  8. export const order0 = orderFactory(0);
  9. ...
  10. export const order15 = orderFactory(15);
复制代码
query.ts
  1. import * as schema from './db/schema';
  2. const db = drizzle(process.env.DATABASE_URL!, { schema });
  3. const userId = 129;
  4. const modelName=`order${userId % 16}`;
  5. const orders = await db.query[modelName].findMany();
复制代码
Prisma ORM

Prisma ORM对动态表名的支持还在规划当中,参见:Table Partitioning
作为备选方案,我们可以使用$queryRawUnsafe直接构造原始SQL:
  1. const userId = 129;
  2. const tableName = `Order_${userId % 16}`;  
  3. const orders = await prisma.$queryRawUnsafe(`SELECT * FROM "${tableName}"`);
复制代码
Vona ORM

Vona ORM提供了两种模式:自动模式/手工模式
1. 自动模式

model/order.ts
  1. import { EntityOrder } from '../entity/order.ts';
  2. @Model({
  3.   entity: EntityOrder,
  4.   table(ctx: VonaContext, defaultTable: keyof ITableRecord) {
  5.     const user = ctx.app.bean.passport.getCurrentUser();
  6.     if (!user) return defaultTable;
  7.     return `${defaultTable}_${Number(user.id) % 16}`;
  8.   },
  9. })
  10. export class ModelOrder {}
复制代码

  • defaultTable: 是在EntityOrder中定义的缺省表名,如:Order
service/order.ts
  1. class ServiceOrder {
  2.   async findAll() {
  3.     return await this.scope.model.order.select();
  4.   }
  5. }
复制代码
2. 手工模式

service/order.ts
  1. class ServiceOrder {
  2.   async findAll() {
  3.     const user = this.bean.passport.getCurrentUser();
  4.     const tableName = `Order_${Number(user!.id) % 16}`;
  5.     const modelOrder = this.scope.model.order.newInstance(undefined, tableName as any);
  6.     return await modelOrder.select();
  7.   }
  8. }
复制代码

  • newInstance: 第一个参数可以传入数据源,从而实现分库能力。这里忽略,因此传入undefined

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册