nestjs实战(四):一套代码同时连接达梦数据库与MySQL(国产化项目必备)
今天这篇保姆级教程,手把手教你用 NestJS + TypeORM 自定义数据源,实现一套代码无缝切换达梦数据库和MySQL!全程实战代码,从环境搭建到CRUD完整示例,让你在国产化项目中既能享受达梦的合规性,又能保留MySQL的开发便利性。
数据库连接模块可以打包直接复用。
如果你觉得有用,请关注、点赞👍、收藏🌟、评论💬支持一下!文末还有粉丝福利!
1. 先搞懂核心原理
NestJS 本身不实现 ORM,而是通过模块化集成 TypeORM。但官方 @nestjs/typeorm 模块对达梦这种非原生数据库支持不够友好,容易遇到 oracledb 驱动冲突、方言包补丁失效等问题。
我们的解决方案:
-
放弃
@nestjs/typeorm,改用自定义提供者手动创建数据源。 -
通过环境变量
DB_TYPE动态选择创建 MySQL 数据源(DataSource)或 达梦数据源(DmdbDataSource)。 -
将创建好的数据源实例通过
'DATA_SOURCE'令牌注入到各个服务中。
优势:
✅ 彻底避免驱动冲突,连接更稳定
✅ 一套 Service 代码,无需修改即可操作两种数据库
✅ 完全掌控数据库连接生命周期
2. 环境准备与依赖安装
Node.js 版本要求
-
推荐 Node.js 16.x 或 18.x LTS(达梦驱动对高版本支持不完善)
-
可用
nvm或nvm-windows管理版本
创建项目并安装依赖
bash
# 创建 NestJS 项目
nest new nest-dm-mysql-demo
cd nest-dm-mysql-demo
# 安装必要依赖(注意:不安装 @nestjs/typeorm)
npm install @nestjs/config typeorm mysql2 dmdb typeorm-dm reflect-metadata
依赖说明:
-
@nestjs/config:读取环境变量 -
typeorm:TypeORM 核心(被typeorm-dm依赖) -
mysql2:MySQL 驱动 -
dmdb:达梦官方 Node.js 驱动 -
typeorm-dm:达梦方言包(提供DmdbDataSource)
3. 配置环境变量(核心!)
在项目根目录创建 .env 文件,通过 DB_TYPE 控制使用哪种数据库:
env
# 数据库类型:mysql 或 dm
DB_TYPE=mysql
# 通用数据库连接信息
DB_HOST=localhost
DB_USERNAME=root
DB_PASSWORD=123456
# MySQL 专用配置
MYSQL_PORT=3306
MYSQL_DB=test_db
# 达梦专用配置
DM_PORT=5236
DM_SCHEMA=TEST # 达梦模式名,通常与用户名相同
切换数据库只需修改 DB_TYPE 这一个变量!
4. 数据库模块:动态创建数据源(关键代码)
创建 src/database/database.module.ts,这是整个方案的核心:
import { Module, Global, Logger } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { DataSource } from 'typeorm';
import { DmdbDataSource } from 'typeorm-dm';
import { User } from '../user/user.entity';
@Global()
@Module({
imports: [ConfigModule],
providers: [
{
provide: 'DATA_SOURCE',
useFactory: async (configService: ConfigService) => {
const logger = new Logger('DatabaseModule');
const dbType = configService.get<string>('DB_TYPE');
let dataSource: DataSource;
if (dbType === 'mysql') {
// MySQL 数据源
dataSource = new DataSource({
type: 'mysql',
host: configService.get<string>('DB_HOST'),
port: configService.get<number>('MYSQL_PORT'),
username: configService.get<string>('DB_USERNAME'),
password: configService.get<string>('DB_PASSWORD'),
database: configService.get<string>('MYSQL_DB'),
entities: [User],
synchronize: true, // 开发环境使用,生产请关闭
logging: false,
});
} else if (dbType === 'dm') {
// 达梦数据源
dataSource = new DmdbDataSource({
type: 'oracle',
innerType: 'dmdb',
host: configService.get<string>('DB_HOST'),
port: configService.get<number>('DM_PORT'),
username: configService.get<string>('DB_USERNAME'),
password: configService.get<string>('DB_PASSWORD'),
schema: configService.get<string>('DM_SCHEMA'),
entities: [User],
synchronize: true,
logging: false,
extra: {
connectTimeout: 30000,
loginEncrypt: false, // 避免达梦加密错误
},
});
} else {
throw new Error(`不支持的数据库类型: ${dbType}`);
}
await dataSource.initialize();
logger.log(`${dbType} 数据库连接成功!`);
return dataSource;
},
inject: [ConfigService],
},
],
exports: ['DATA_SOURCE'],
})
export class DatabaseModule {}
要点说明:
-
type: 'oracle'和innerType: 'dmdb'是达梦方言包的固定写法。 -
loginEncrypt: false用于解决达梦加密错误[6071]。 -
entities数组注册了所有实体,可随时添加。
5. 定义用户实体
创建 src/user/user.entity.ts:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity('t_user')
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 50 })
name: string;
@Column({ type: 'int', nullable: true })
age: number;
}
注意:实体定义完全兼容两种数据库,无需任何修改。
6. 用户模块与服务
用户模块 src/user/user.module.ts
typescript
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
@Module({
providers: [UserService],
controllers: [UserController],
})
export class UserModule {}
用户服务 src/user/user.service.ts
typescript
import { Injectable, Inject, NotFoundException } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UserService {
private userRepository: Repository<User>;
constructor(@Inject('DATA_SOURCE') private dataSource: DataSource) {
this.userRepository = this.dataSource.getRepository(User);
}
async create(userData: Partial<User>): Promise<User> {
const user = this.userRepository.create(userData);
return this.userRepository.save(user);
}
async findAll(): Promise<User[]> {
return this.userRepository.find();
}
async findOne(id: number): Promise<User | null> {
return this.userRepository.findOneBy({ id });
}
async update(id: number, updateData: Partial<User>): Promise<User> {
const user = await this.findOne(id);
if (!user) {
throw new NotFoundException(`用户 ID ${id} 不存在`);
}
Object.assign(user, updateData);
return this.userRepository.save(user);
}
async remove(id: number): Promise<void> {
const result = await this.userRepository.delete(id);
if (result.affected === 0) {
throw new NotFoundException(`用户 ID ${id} 不存在`);
}
}
}
关键点:服务中注入的是 DataSource 类型,无论底层是 MySQL 还是达梦,都能正确获取 Repository。
用户控制器 src/user/user.controller.ts
typescript
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
create(@Body() userData: Partial<User>): Promise<User> {
return this.userService.create(userData);
}
@Get()
findAll(): Promise<User[]> {
return this.userService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): Promise<User | null> {
return this.userService.findOne(+id);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateData: Partial<User>): Promise<User> {
return this.userService.update(+id, updateData);
}
@Delete(':id')
remove(@Param('id') id: string): Promise<void> {
return this.userService.remove(+id);
}
}
7. 根模块整合
修改 src/app.module.ts,导入数据库模块和用户模块:
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { DatabaseModule } from './database/database.module';
import { UserModule } from './user/user.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
}),
DatabaseModule,
UserModule,
],
})
export class AppModule {}
8. 运行测试
启动应用
bash
npm run start:dev
看到如下日志表示连接成功:
text
[Nest] ... LOG [DatabaseModule] mysql 数据库连接成功! 或 [Nest] ... LOG [DatabaseModule] dm 数据库连接成功!
测试 CRUD 接口
| 方法 | 路径 | 功能 | 请求体示例 |
|---|---|---|---|
| POST | /users |
创建用户 | {"name": "张三", "age": 30} |
| GET | /users |
获取所有用户 | - |
| GET | /users/:id |
获取单个用户 | - |
| PUT | /users/:id |
更新用户 | {"age": 35} |
| DELETE | /users/:id |
删除用户 | - |
使用 Postman 或 curl 测试:
bash
# 创建用户
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"name":"李四","age":25}'
# 查询所有用户
curl http://localhost:3000/users


9. 常见问题与解决方案
❌ 问题1:达梦连接时报 [6071] 消息加密失败
解决:在达梦配置的 extra 中添加 loginEncrypt: false。
❌ 问题2:启动后仍提示 Oracle package not found
原因:typeorm-dm 的补丁未生效,或错误地安装了 @nestjs/typeorm。
解决:确保卸载 @nestjs/typeorm,并删除 node_modules 重新安装。
❌ 问题3:MySQL 连接时区问题
解决:在 MySQL 配置中添加 timezone: 'Z' 或 timezone: '+08:00'。
❌ 问题4:Node.js 版本过高导致编译失败
解决:降级到 Node.js 16 或 18 LTS。
如果你觉得有用,请点赞👍、收藏🌟、评论💬支持一下!文末还有粉丝福利!
粉丝提供完整源码!
更多推荐

所有评论(0)