将 TypeOrm 与 NestJs 结合使用时从 Master 中选择查询

问题描述 投票:0回答:2

设置信息


在解决实际问题之前,让我向您解释一下架构设置。所以我们有一个带有主从配置Postgres集群。在这个集群中,我们使用了同步复制策略sychronous_commit作为remote_apply

供参考:https://www.percona.com/blog/2020/08/21/postgresql-synchronous_commit-options-and-synchronous-standby-replication/


问题陈述


我们将 TypeOrm 与 NestJs 结合使用(不详细介绍模块如何实例化以及连接如何发生,请考虑它正在发生,并且我们能够通过 TypeOrm 创建的连接获取数据)。

我们已经公开了某些函数来通过 TypeOrm API 与表对话。

问题是,当我们在任何表上执行选择查询时,它会自动尝试从 Postgres 集群的 SLAVE 获取它。


查询


是否有任何 Typeorm api 选项可用,通过它我们可以告诉 TypeOrm,对于特定调用请不要转到 Slave,而是转到 master 来执行。

今天我们使用的是这样的东西:

    /**
      PLEASE CONSIDER ALL IMPORTS AND CONFIGS WORKING PERFECTLY FINE FOR NESTJS
    */
    export class SomeClassName {
        constructor(@InjectRepository(ENTITYNAME) private readonly entityRepository: Repository<Entity>) {}

        /**
         *
         * @description this function finds the record from the db and return it
         * @param id the record that needs to be returned
         */
        async findSomething(id: string): Promise<Entity> {
            /**
             * This call is going to PG Cluster Slave since its a SELECT call (behind the scenes).
             * What we want, is for this call, we will pass any FLAG or ANY config,
             * that forces TYPEORM to get this specific data from MASTER
             */
            return this.entityRepository.findOne({ job_id: id });
        }
    }

如果存储库模式无法实现,是否有其他方法可以告诉 Typeorm 从 Master 获取数据?

请发表一些看法。快乐编码:)

nestjs typeorm pg master-slave nestjs-typeorm
2个回答
0
投票

解决方案是注入 EntityManager 并创建指定数据库的查询运行器

const queryRunner = this.entityManager.connection.createQueryRunner('master')

然后使用

queryRunner.manager(Entity, query)

0
投票

理想的解决方案是为数据库配置 typeorm MASTER 和 SLAVE 服务器 像这样的东西应该对你有用

所有插入都将通过主设备进行,读取将在从设备之间均匀重定向

function getOptions(): DataSourceOptions {
    const type = 'postgres';
    const logging = process.env.DB_LOGGING === 'true';
    const synchronize = process.env.DB_SYNCHRONIZE === 'true';
    const entities = [path.resolve(__dirname, 'src', '**', 'entities/*{index.ts,.entity.ts,.entity.js}')];
    const migrations = [path.resolve(__dirname, 'src', 'database', 'migrations/*{.ts,.js}')];
    const migrationsRun = process.env.DB_MIGRATIONS_RUN === 'true';

    if (process.env.DB_REPLICATION === 'true') {
        const master = {
            host: process.env.DB_HOST_MASTER,
            port: Number.parseInt(process.env.DB_PORT_MASTER ?? '', 10),
            username: process.env.DB_USERNAME_MASTER,
            password: process.env.DB_PASSWORD_MASTER,
            database: process.env.DB_NAME_MASTER
        };

        const slaves: PostgresConnectionCredentialsOptions[] = [];

        for (let i = 0; ; i++) {
            if (process.env[`DB_HOST_SLAVE_${i}`]) {
                slaves.push({
                    host: process.env[`DB_HOST_SLAVE_${i}`],
                    port: Number.parseInt(process.env[`DB_PORT_SLAVE_${i}`] ?? '', 10),
                    username: process.env[`DB_USERNAME_SLAVE_${i}`],
                    password: process.env[`DB_PASSWORD_SLAVE_${i}`],
                    database: process.env[`DB_NAME_SLAVE_${i}`]
                });
            } else {
                break;
            }
        }
        return {
            type,
            replication: {
                master,
                slaves
            },
            logging,
            synchronize,
            entities,
            migrations,
            migrationsRun
        };
    } else {
        return {
            type,
            host: process.env.DB_HOST,
            port: Number.parseInt(process.env.DB_PORT ?? '', 10),
            username: process.env.DB_USERNAME,
            password: process.env.DB_PASSWORD,
            database: process.env.DB_NAME,
            logging,
            synchronize,
            entities,
            migrations,
            migrationsRun
        };
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.