typeorm核心之Connection类


src/connection/Connection.ts

//一个连接对应一个数据库,根据数据库类型,可以创建连接池
export class Connection {
    //连接名称,默认为default
    readonly name: string;
    //连接选项
    readonly options: ConnectionOptions;
    //是否已经连接
    readonly isConnected = false;
    //数据库驱动,对应了不同数据库,执行数据库操作的最基本对象QueryRunner就是使用Driver创建的
    readonly driver: Driver;
    //实体管理器,一个连接对应一个实体管理器,实体关联器是Repository用来执行数据库操作的内部对象
    //实体管理器内部还是使用Connection创建QueryRunner、QueryBuilder等来执行操作
    //所以本质上还是使用Driver
    readonly manager: EntityManager;
    //命名策略,当用户未指定时,用来确定表名、列名等与实体类的关系
    readonly namingStrategy: NamingStrategyInterface;
    //日志记录器
    readonly logger: Logger;
    //迁移对象数组,每个迁移类有一个up一个down方法
    //迁移的up方法会在connect方法中执行
    readonly migrations: MigrationInterface[] = [];
    //实体订阅对象数组,每个实体订阅类上面有一些与数据库触发器类似的方法
    readonly subscribers: EntitySubscriberInterface[] = [];
    //连接对应数据库中,所有注册实体的元数据
    readonly entityMetadatas: EntityMetadata[] = [];
    //查询结果缓存,这里为接口,实现中可以缓存到当前数据库,也可以缓存到Redis
    readonly queryResultCache?: QueryResultCache;
    //使用连接选项初始化
    constructor(options: ConnectionOptions) {
        //默认连接名称为default
        this.name = options.name || "default";
        this.options = options;
        //日志记录器
        this.logger = new LoggerFactory().create(this.options.logger, this.options.logging);
        //由驱动工厂创建驱动,根据连接类型不同,驱动实现类也不同
        this.driver = new DriverFactory().create(this);
        //创建实体管理器,根据数据库类型不同,也会创建不同类型实体管理器,如Mongodb、sqljs等
        this.manager = this.createEntityManager();
        //创建命名策略
        this.namingStrategy = options.namingStrategy || new DefaultNamingStrategy();
        //根据选项设置查询结果缓存对象,由工厂根据选项创建不同的实现类对象
        this.queryResultCache = options.cache ? new QueryResultCacheFactory(this).create() : undefined;
    }

    //获取mongodb实体管理器
    get mongoManager(): MongoEntityManager {
        //如果实体管理器类型不是Mongodb的,抛出错误
        if (!(this.manager instanceof MongoEntityManager))
            throw new Error(`MongoEntityManager is only available for MongoDB databases.`);
        return this.manager as MongoEntityManager;
    }
    //获取sqljs实体管理器
    get sqljsManager(): SqljsEntityManager {
        if (!(this.manager instanceof SqljsEntityManager))
            throw new Error(`SqljsEntityManager is only available for Sqljs databases.`);
        return this.manager as SqljsEntityManager;
    }

    //执行连接
    //这一步连接了驱动、构建了元数据、根据选项对数据库进行删除、同步操作、运行迁移
    async connect(): Promise {
        //如果已经连接,抛出异常
        if (this.isConnected)
            throw new CannotConnectAlreadyConnectedError(this.name);
        //使用驱动连接
        await this.driver.connect();
        //如果由查询结果缓存,连接它
        if (this.queryResultCache)
            await this.queryResultCache.connect();
        //设置连接状态
        Object.assign(this, { isConnected: true });
        try {
            //构建元数据
            this.buildMetadatas();
            //调用连接后方法
            await this.driver.afterConnect();
            //如果选项设置了dropSchema,则删除对应数据库表
            if (this.options.dropSchema)
                await this.dropDatabase();
            //如果由同步选项,则将当前实体信息与数据库表同步
            if (this.options.synchronize)
                await this.synchronize();
            //运行迁移
            if (this.options.migrationsRun)
                await this.runMigrations();
        } catch (error) {
            await this.close();
            throw error;
        }
        return this;
    }

    //关闭连接
    async close(): Promise {
        if (!this.isConnected)
            throw new CannotExecuteNotConnectedError(this.name);
        //使用驱动断开连接
        await this.driver.disconnect();
        //断开查询缓存
        if (this.queryResultCache)
            await this.queryResultCache.disconnect();
        //设置连接状态为false
        Object.assign(this, { isConnected: false });
    }

    //实体与数据库表结构同步,参数为是否先删除数据库表,connect中调用只是同步、不删除
    async synchronize(dropBeforeSync: boolean = false): Promise {
        if (!this.isConnected)
            throw new CannotExecuteNotConnectedError(this.name);
        //先删除数据库
        if (dropBeforeSync)
            await this.dropDatabase();
        //使用驱动获取schema构建器
        const schemaBuilder = this.driver.createSchemaBuilder();
        //构建表结构,这一步查询当前连接中实体类所对应表的列类型,与实体对比,进行修改
        await schemaBuilder.build();
    }

    //删除数据库表
    async dropDatabase(): Promise {
        //获取查询运行器
        const queryRunner = await this.createQueryRunner("master");
        //过滤出所有元数据中的schema
        const schemas = this.entityMetadatas
            .filter(metadata => metadata.schema)
            .map(metadata => metadata.schema!);
        //如果是SqlServer、Mysql驱动
        if (this.driver instanceof SqlServerDriver || this.driver instanceof MysqlDriver) {
            //获取数据库名数组,第一个元素为主数据库名,即默认情况下数据库名
            const databases: string[] = this.driver.database ? [this.driver.database] : [];
            //遍历实体元数据,获取实体中出现的所有数据库名
            this.entityMetadatas.forEach(metadata => {
                //如果实体元数据中指定数据库不是连接中指定的数据库名,加入数组中
                if (metadata.database && databases.indexOf(metadata.database) === -1)
                    databases.push(metadata.database);
            });
            //使用查询运行器删除数据库中的表
            await PromiseUtils.runInSequence(databases, database => queryRunner.clearDatabase(schemas, database));
        } else {
            await queryRunner.clearDatabase(schemas);
        }
        await queryRunner.release();
    }

    //允许迁移
    async runMigrations(): Promise {
        if (!this.isConnected)
            throw new CannotExecuteNotConnectedError(this.name);
        //获取迁移执行器
        const migrationExecutor = new MigrationExecutor(this);
        //执行迁移,其实就是执行所有迁移对象的up方法
        await migrationExecutor.executePendingMigrations();
    }

    //移除最后一次迁移,即执行最后一个迁移对象的down方法
    async undoLastMigration(): Promise {
        if (!this.isConnected)
            throw new CannotExecuteNotConnectedError(this.name);
        const migrationExecutor = new MigrationExecutor(this);
        await migrationExecutor.undoLastMigration();
    }

    //是否包含指定类,schema名的元数据
    hasMetadata(target: Function|string): boolean {
        return !!this.findMetadata(target);
    }

    //获取指定实体类或者schema的元数据
    getMetadata(target: Function|string): EntityMetadata {
        const metadata = this.findMetadata(target);
        if (!metadata)
            throw new EntityMetadataNotFound(target);
        return metadata;
    }

    //获取指定实体类的仓库
    getRepository(target: ObjectType|string): Repository {
        //由实体管理器创建仓库
        return this.manager.getRepository(target);
    }

    //获取指定实体类的树状仓库
    getTreeRepository(target: ObjectType|string): TreeRepository {
        return this.manager.getTreeRepository(target);
    }

    //获取mongodb仓库,只有驱动为相应类型才可以获取
    getMongoRepository(target: ObjectType|string): MongoRepository {
        if (!(this.driver instanceof MongoDriver))
            throw new Error(`You can use getMongoRepository only for MongoDB connections.`);
        return this.manager.getRepository(target) as any;
    }

    //获取定制仓库
    getCustomRepository(customRepository: ObjectType): T {
        return this.manager.getCustomRepository(customRepository);
    }

    //在一个事务中运行指定参数方法,方法使用实体管理器进行数据库操作,这些操作都是在一个事务当中
    //好像不需要显式开启事务、提交、回滚,加入抛出错误,会自动回滚
    async transaction(runInTransaction: (entityManger: EntityManager) => Promise): Promise {
        return this.manager.transaction(runInTransaction);
    }

    //执行原始sql查询,返回原始查询结果
    async query(query: string, parameters?: any[], queryRunner?: QueryRunner): Promise {
        //mongodb没有原始sql查询
        if (this instanceof MongoEntityManager)
            throw new Error(`Queries aren't supported by MongoDB.`);
        //查询运行器已释放,抛出错误
        if (queryRunner && queryRunner.isReleased)
            throw new QueryRunnerProviderAlreadyReleasedError();
        //未指定查询运行器时,使用master查询运行器,即从主数据库获取的查询运行器
        const usedQueryRunner = queryRunner || this.createQueryRunner("master");
        try {
            //使用查询运行器允许原始sql查询
            return await usedQueryRunner.query(query, parameters);  // await is needed here because we are using finally
        } finally {
            if (!queryRunner)
            //最后释放查询运行器
                await usedQueryRunner.release();
        }
    }

    //获取指定实体类的查询构建器,并对类设置别名,查询构建器也是使用查询运行器创建
    createQueryBuilder(entityClass: ObjectType|Function|string, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder;
    createQueryBuilder(queryRunner?: QueryRunner): SelectQueryBuilder;
    createQueryBuilder(entityOrRunner?: ObjectType|Function|string|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder {
        //Mongodb没有查询构建器
        if (this instanceof MongoEntityManager)
            throw new Error(`Query Builder is not supported by MongoDB.`);
        //如果设置别名
        if (alias) {
            //获取指定实体类元数据
            const metadata = this.getMetadata(entityOrRunner as Function|string);
            //返回select查询构建器,并设置别名
            return new SelectQueryBuilder(this, queryRunner)
                //别名使用select设置
                .select(alias)
                .from(metadata.target, alias);

        } 
        //未设置别名
        else {
            return new SelectQueryBuilder(this, entityOrRunner as QueryRunner|undefined);
        }
    }

    //创建查询运行器,在一个单独的数据库连接中进行查询
    //mode代表了连接的目的,在开启主从复制模式时,如果执行写操作为master,执行读操作为slave
    createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner {
        //使用驱动创建查询构建器
        const queryRunner = this.driver.createQueryRunner(mode);
        //生成实体管理器
        const manager = this.createEntityManager(queryRunner);
        //实体管理器为查询运行器的属性,他俩互相有对方的引用
        Object.assign(queryRunner, { manager: manager });
        return queryRunner;
    }

    //获取指定实体的many-to-many关系的连接表元数据
    //第一个参数为实体类,第二个参数为many-to-many属性
    getManyToManyMetadata(entityTarget: Function|string, relationPropertyPath: string) {
        //获取实体元数据上指定属性的关系元数据
        const relationMetadata = this.getMetadata(entityTarget).findRelationWithPropertyPath(relationPropertyPath);
        if (!relationMetadata)
            throw new Error(`Relation "${relationPropertyPath}" was not found in ${entityTarget} entity.`);
        //关系元数据不是many-to-many类型
        if (!relationMetadata.isManyToMany)
            throw new Error(`Relation "${entityTarget}#${relationPropertyPath}" does not have a many-to-many relationship.` +
                `You can use this method only on many-to-many relations.`);
        //返回关系元数据上的连接实体元数据
        return relationMetadata.junctionEntityMetadata;
    }

    //创建实体管理器
    createEntityManager(queryRunner?: QueryRunner): EntityManager {
        //这里根据不同连接类型创建不同类型实体管理器,如Mongodb、sqljs
        return new EntityManagerFactory().create(this, queryRunner);
    }

    //查找指定实体类或者表名的元数据
    protected findMetadata(target: Function|string): EntityMetadata|undefined {
        return this.entityMetadatas.find(metadata => {
            //如果类构造函数相等返回它
            if (metadata.target === target)
                return true;
            //字符串参数
            if (typeof target === "string") {
                //名称包含.
                if (target.indexOf(".") !== -1) {
                    //根据表路径查找
                    return metadata.tablePath === target;
                } 
                //不包含.
                else {
                    //根据表名查找
                    return metadata.name === target || metadata.tableName === target;
                }
            }
            return false;
        });
    }

    //构建连接中所有注册实体的元数据
    protected buildMetadatas(): void {
        //连接元数据构建器
        const connectionMetadataBuilder = new ConnectionMetadataBuilder(this);
        //实体元数据验证器
        const entityMetadataValidator = new EntityMetadataValidator();
        //根据选项创建订阅者
        const subscribers = connectionMetadataBuilder.buildSubscribers(this.options.subscribers || []);
        //设置订阅者
        Object.assign(this, { subscribers: subscribers });
        //根据选项中实体构建实体元数据
        const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas(this.options.entities || [], this.options.entitySchemas || []);
        Object.assign(this, { entityMetadatas: entityMetadatas });
        //根据选项构建迁移对象
        const migrations = connectionMetadataBuilder.buildMigrations(this.options.migrations || []);
        Object.assign(this, { migrations: migrations });
        //验证元数据是否符合数据库驱动
        entityMetadataValidator.validateMany(this.entityMetadatas, this.driver);
    }
}


1.连接中包含了数据库驱动,不同数据库类型有不同数据库驱动

2.运行查询的三个类

QueryRuner:查询运行器,对应了一个真实的数据库连接,即一个连接池中的连接,如mysql包连接池中的连接

EntityManager:使用查询运行器创建

QueryBuilder:也是使用查询运行器创建

还有一个query方法来执行原始sql查询,也是使用查询运行器查询

你可能感兴趣的:(typeorm)