node下的TypeORM比上不足,比下有余,这里分享一些使用经验
TypeORM提供的入口很多,connection,entityManager,repo,使用的时候难免纠结用什么,这里建议统一使用entityManager:
getManager()
建议封装事务,动态传入entityManager,方便复用和测试:
import { EntityManager, getManager } from 'typeorm';
import { IsolationLevel } from 'typeorm/driver/types/IsolationLevel';
export const runInTransaction = async (callback: any, options?: any) => {
const connectionName = options?.connectionName ?? 'default';
const isolationLevel: IsolationLevel | undefined = options?.isolationLevel;
if (!options?.entityManager) {
await getManager(connectionName).transaction(
isolationLevel,
async (entityManager: EntityManager) => await callback(entityManager),
);
} else {
await callback(options?.entityManager);
}
};
在NestJS下,我们默认在app.module.ts里配置连接:
TypeOrmModule.forRootAsync({
useFactory: async (config: ConfigService) => config.get('database'),
inject: [ConfigService],
}),
有的时候我们想要自己控制连接,比如允许数据库连接失败,这时候就需要换一种方式:
初始化:主动触发createConnection并允许失败
import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ConnectionOptions, createConnection } from 'typeorm';
@Injectable()
export class AppService implements OnApplicationBootstrap {
constructor(
private readonly config: ConfigService,
) {}
async onApplicationBootstrap() {
try {
await createConnection(this.config.get<ConnectionOptions>('database'));
} catch (error) {}
}
}
获取连接
export const getCustomConnection = async (connectionName?: string) => {
let connection = getConnection(connectionName ?? 'default');
// 防止初始化时连接失败
if (!connection.isConnected) {
await connection.connect();
};
return connection;
};
建议使用真实数据库,通过事务管理测试:
describe('TestService', () => {
let repository: Repository<Test>;
let service: TestService;
let connection: Connection;
let queryRunner: QueryRunner;
beforeAll(async () => {
// 超时
jest.setTimeout(1000 * 60);
// 使用Nest方式注入
const moduleRef = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({
load: appConfig,
isGlobal: true,
}),
TypeOrmModule.forRoot(TypeOrmTestConfig)
],
}).compile();
// 创建queryRunner
connection = getConnection();
queryRunner = connection.createQueryRunner();
await queryRunner.connect();
let configService = moduleRef.get<ConfigService>(ConfigService);
repository = queryRunner.manager.getRepository(Test);
service = new TestService(
repository,
configService,
);
});
beforeEach(async () => {
// 开启事务
await queryRunner.startTransaction();
});
afterEach(async () => {
// 回滚事务
await queryRunner.rollbackTransaction();
});
afterAll(async () => {
// 释放queryRunner
await queryRunner.release();
});
it('test', async () => {
const test = await queryRunner.manager.findOne(Test, 1);
expect(test).not.toBeUndefined();
});
});
避免使用em.save,单独使用em.insert和em.update;
生产环境禁止启用synchronize,使用migrationsRun;
sqlserver因为node的问题,要配置options: {encrypt: false}
;