news 2026/7/24 8:45:17

NestJS 实战(四):一套代码同时连接达梦数据库与MySQL(国产化项目必备)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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(达梦驱动对高版本支持不完善)

  • 可用nvmnvm-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。

如果你觉得有用,请点赞👍、收藏🌟、评论💬支持一下!文末还有粉丝福利!

粉丝提供完整源码!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 14:23:36

高算Linux平台离线部署gprMax:从环境配置到实战仿真的完整避坑指南

1. 离线部署gprMax的挑战与解决方案 在科研机构和企业的封闭计算环境中&#xff0c;高性能Linux服务器通常采用严格的网络隔离策略。这种情况下部署gprMax这类依赖复杂Python生态的电磁仿真工具&#xff0c;就像在没有超市的荒岛上搭建厨房——你需要提前准备好所有食材。我最近…

作者头像 李华
网站建设 2026/7/24 8:43:51

Nanbeige 4.1-3B实操手册:添加对话历史导出为像素风格PDF功能

Nanbeige 4.1-3B实操手册&#xff1a;添加对话历史导出为像素风格PDF功能 1. 项目背景与功能概述 Nanbeige 4.1-3B是一款融合了复古像素游戏风格的AI对话前端&#xff0c;专为提升用户交互体验而设计。最新版本新增了对话历史导出功能&#xff0c;可以将整个对话过程保存为像…

作者头像 李华
网站建设 2026/7/14 14:23:47

TinyNAS WebUI可视化开发:零基础JavaScript调用指南

TinyNAS WebUI可视化开发&#xff1a;零基础JavaScript调用指南 用最简单的方式&#xff0c;让前端开发者快速上手TinyNAS WebUI的检测功能 1. 开篇&#xff1a;为什么前端开发者需要了解TinyNAS&#xff1f; 作为一名前端开发者&#xff0c;你可能经常遇到这样的需求&#xf…

作者头像 李华
网站建设 2026/7/14 14:23:49

HarmonyOS 6实战:TextInput获焦时提示文本动态上移效果实现

问题背景在HarmonyOS应用开发中&#xff0c;TextInput组件作为最常用的文本输入控件&#xff0c;其用户体验直接影响到应用的交互质量。传统的TextInput组件在获焦时&#xff0c;提示文本&#xff08;placeholder&#xff09;会直接消失&#xff0c;用户需要依赖短期记忆来确认…

作者头像 李华
网站建设 2026/7/14 14:23:50

ClawdBot高算力适配:vLLM加持下GPU显存占用降低40%的实测优化教程

ClawdBot高算力适配&#xff1a;vLLM加持下GPU显存占用降低40%的实测优化教程 1. 项目概述与优化价值 ClawdBot是一个可以在个人设备上运行的AI助手应用&#xff0c;它使用vLLM提供后端模型能力。在实际部署中&#xff0c;很多用户发现原版配置对GPU显存的要求较高&#xff0…

作者头像 李华