只读副本
当你的项目涉及一组只读副本实例,并且你需要一种便捷的方法来管理从只读副本执行的 SELECT 查询,以及在主实例上执行创建、删除和更新操作时,你可以利用 Drizzle 中的 withReplicas()
函数。
import { sql } from 'drizzle-orm' ;
import { drizzle } from 'drizzle-orm/node-postgres' ;
import { boolean , jsonb , pgTable , serial , text , timestamp , withReplicas } from 'drizzle-orm/pg-core' ;
const usersTable = pgTable ( 'users' , {
id : serial ( 'id' as string ) .primaryKey () ,
name : text ( 'name' ) .notNull () ,
verified : boolean ( 'verified' ) .notNull () .default ( false ) ,
jsonb : jsonb ( 'jsonb' ) .$type < string []>() ,
createdAt : timestamp ( 'created_at' , { withTimezone : true }) .notNull () .defaultNow () ,
});
const primaryDb = drizzle ( "postgres://user:password@host:port/primary_db" );
const read1 = drizzle ( "postgres://user:password@host:port/read_replica_1" );
const read2 = drizzle ( "postgres://user:password@host:port/read_replica_2" );
const db = withReplicas (primaryDb , [read1 , read2]);
import { drizzle } from "drizzle-orm/mysql2" ;
import mysql from "mysql2/promise" ;
import { boolean , mysqlTable , serial , text , withReplicas } from 'drizzle-orm/mysql-core' ;
const usersTable = mysqlTable ( 'users' , {
id : serial ( 'id' as string ) .primaryKey () ,
name : text ( 'name' ) .notNull () ,
verified : boolean ( 'verified' ) .notNull () .default ( false ) ,
});
const primaryClient = await mysql .createConnection ({
host : "host" ,
user : "user" ,
database : "primary_db" ,
})
const primaryDb = drizzle ({ client : primaryClient });
const read1Client = await mysql .createConnection ({
host : "host" ,
user : "user" ,
database : "read_1" ,
})
const read1 = drizzle ({ client : read1Client });
const read2Client = await mysql .createConnection ({
host : "host" ,
user : "user" ,
database : "read_2" ,
})
const read2 = drizzle ({ client : read2Client });
const db = withReplicas (primaryDb , [read1 , read2]);
import { sql } from 'drizzle-orm' ;
import { sqliteTable , int , text , withReplicas } from 'drizzle-orm/sqlite-core' ;
import { createClient } from '@libsql/client' ;
import { drizzle } from 'drizzle-orm/libsql' ;
const usersTable = sqliteTable ( 'users' , {
id : int ( 'id' as string ) .primaryKey () ,
name : text ( 'name' ) .notNull () ,
});
const primaryDb = drizzle ({ client : createClient ({ url : 'DATABASE_URL' , authToken : 'DATABASE_AUTH_TOKEN' }) });
const read1 = drizzle ({ client : createClient ({ url : 'DATABASE_URL' , authToken : 'DATABASE_AUTH_TOKEN' }) });
const read2 = drizzle ({ client : createClient ({ url : 'DATABASE_URL' , authToken : 'DATABASE_AUTH_TOKEN' }) });
const db = withReplicas (primaryDb , [read1 , read2]);
import { drizzle } from "drizzle-orm/singlestore" ;
import mysql from "mysql2/promise" ;
import { boolean , singlestoreTable , serial , text , withReplicas } from 'drizzle-orm/singlestore-core' ;
const usersTable = singlestoreTable ( 'users' , {
id : serial ( 'id' as string ) .primaryKey () ,
name : text ( 'name' ) .notNull () ,
verified : boolean ( 'verified' ) .notNull () .default ( false ) ,
});
const primaryClient = await mysql .createConnection ({
host : "host" ,
user : "user" ,
database : "primary_db" ,
})
const primaryDb = drizzle ({ client : primaryClient });
const read1Client = await mysql .createConnection ({
host : "host" ,
user : "user" ,
database : "read_1" ,
})
const read1 = drizzle ({ client : read1Client });
const read2Client = await mysql .createConnection ({
host : "host" ,
user : "user" ,
database : "read_2" ,
})
const read2 = drizzle ({ client : read2Client });
const db = withReplicas (primaryDb , [read1 , read2]);
你现在可以像以前一样使用 db
实例。Drizzle 将自动处理只读副本和主实例之间的选择。
// Read from either the read1 connection or the read2 connection
await db .select () .from (usersTable)
// Use the primary database for the delete operation
await db .delete (usersTable) .where ( eq ( usersTable .id , 1 ))
你可以使用 $primary
键强制使用主实例,即使对于读取操作也是如此。
// read from primary
await db . $primary .select () .from (usersTable);
使用 Drizzle,你还可以指定用于选择只读副本的自定义逻辑。你可以对随机读取副本的选择进行加权决策或任何其他自定义选择方法。以下是用于选择只读副本的自定义逻辑的实现示例,其中第一个副本被选中的概率为 70%,第二个副本被选中的概率为 30%。
请记住,你可以为只读副本实现任何类型的随机选择方法。
const db = withReplicas (primaryDb , [read1 , read2] , (replicas) => {
const weight = [ 0.7 , 0.3 ];
let cumulativeProbability = 0 ;
const rand = Math .random ();
for ( const [ i , replica ] of replicas .entries ()) {
cumulativeProbability += weight[i] ! ;
if (rand < cumulativeProbability) return replica;
}
return replicas[ 0 ] !
});
await db .select () .from (usersTable)