当前位置: 首页 > article >正文

nestjs实战(五): 连接达梦数据库的两种方式(完整实战教程)

还在为 NestJS 项目接入达梦数据库发愁想用 TypeORM 优雅操作国产数据库却不知道如何配置今天这篇教程全程围绕 NestJS 与达梦数据库的集成展开从原生驱动连接到 TypeORM 整合详细解释每一步流程和核心代码并以 DMHR.CITY 表为例进行完整演示。1. 先搞懂为什么需要两种方式连接达梦达梦数据库是国内主流的国产关系型数据库但在 Node.js 生态中官方驱动dmdb是 C 插件TypeScript 类型支持不完善。NestJS 作为企业级框架追求代码规范与类型安全这就产生了两种常见方案方案适用场景优点缺点原生驱动方案简单查询、快速原型轻量、直接、无额外依赖类型不安全需手动管理连接TypeORM 方案复杂业务、团队协作ORM 映射、类型安全、迁移方便需配置typeorm-dm扩展2. 准备工作达梦数据库环境搭建2.1 安装达梦数据库从达梦官网下载对应操作系统的 DM8 安装包完成安装。本地测试可使用 Dockerbashdocker run -d -p 5236:5236 \ -e DM_USERSYSDBA \ -e DM_PASSWORDAa123456 \ --name dm8 \ dm8:latest2.2 确认表结构达梦数据库自带示例模式 DMHR包含 CITY 表和 REGION 表REGION 表地区表sqlCREATE TABLE DMHR.REGION ( REGION_ID INT PRIMARY KEY, REGION_NAME VARCHAR(50) ); INSERT INTO DMHR.REGION VALUES (1, 华北地区); INSERT INTO DMHR.REGION VALUES (2, 华东地区); INSERT INTO DMHR.REGION VALUES (3, 华南地区);CITY 表城市表REGION_ID 为外键2.3 安装依赖bashnpm install dmdb typeorm nestjs/typeorm reflect-metadata typeorm-dm注意dmdb是 C 插件需要 Node.js 编译环境Python、Visual Studio Build Tools 或 g。3. 方案一原生驱动连接详细流程3.1 核心代码解析javascriptconst dmdb require(dmdb); class NativeDbService { constructor() { this.logger new Logger(NativeDbService); this.pool null; } async onModuleInit() { try { // 【关键点1】解决 OpenSSL 兼容性问题 process.env.NODE_OPTIONS --openssl-legacy-provider; // 【关键点2】创建连接池 this.pool await dmdb.createPool({ connectionString: dm://SYSDBA:Aa123456localhost:5236/DAMENG?schemaDMHR, poolMax: 10, // 最大连接数 poolMin: 1, // 最小连接数 poolTimeout: 60, // 连接超时时间秒 }); // 【关键点3】测试连接 let testConn; try { testConn await this.pool.getConnection(); this.logger.log(✅ 原生驱动连接成功DMHR 模式); } finally { if (testConn) testConn.release(); // 必须释放连接 } } catch (error) { this.logger.error(❌ 原生驱动连接失败, error); throw error; } } // 【关键点4】获取连接 async getConnection() { return await this.pool.getConnection(); } // 【关键点5】执行 SQL 查询自动释放连接 async query(sql, params []) { const conn await this.getConnection(); try { if (params params.length 0) { const result await conn.execute(sql, params); return result; } else { const result await conn.execute(sql); return result; } } finally { conn.release(); // 无论成功失败都要释放连接 } } // 【关键点6】解析查询结果 async getAllCities() { const sql SELECT * FROM DMHR.CITY ORDER BY CITY_ID; const result await this.query(sql); // 达梦驱动返回的结果格式{ metaData: [...], rows: [...] } if (result result.rows) { const cities result.rows.map(row { const city {}; result.metaData.forEach((col, index) { city[col.name] row[index]; }); return city; }); return cities; } return result; } async onModuleDestroy() { if (this.pool) await this.pool.close(); // 关闭连接池 } }3.2 流程详解步骤1导入驱动使用require(dmdb)而非import因为dmdb没有 TypeScript 类型定义这样可以完全避开 TypeScript 的类型检查步骤2创建连接池createPool是异步方法返回连接池实例connectionString格式dm://用户名:密码主机:端口/数据库?schema模式名连接池参数poolMax最大连接数根据业务并发量设置poolMin最小连接数保持一定数量的活跃连接poolTimeout获取连接的超时时间步骤3测试连接从连接池获取一个连接执行简单查询验证连接有效性重要使用try/finally确保连接被释放步骤4执行查询从连接池获取连接执行 SQL 语句必须释放连接否则连接池会耗尽步骤5结果解析达梦驱动返回{ metaData, rows }格式metaData字段信息数组每个元素有name属性rows数据行数组每行是字段值的数组需要手动转换为对象数组4. 方案二TypeORM 整合详细流程4.1 核心代码解析javascriptconst { DmdbDataSource } require(typeorm-dm); const { EntitySchema } require(typeorm); require(reflect-metadata); // 【关键点1】定义实体使用 EntitySchema const CitySchema new EntitySchema({ name: City, // 实体名称 tableName: CITY, // 数据库表名 schema: DMHR, // 数据库模式名 columns: { CITY_ID: { primary: true, // 主键 type: varchar, // 字段类型 length: 3, // 长度限制 name: CITY_ID // 数据库字段名 }, CITY_NAME: { type: varchar, length: 50, name: CITY_NAME }, REGION_ID: { type: int, name: REGION_ID } } }); // 【关键点2】配置数据源 const typeormConfig { type: oracle, // 达梦兼容 Oracle 协议 innerType: dmdb, // 指定为达梦驱动 host: localhost, port: 5236, username: SYSDBA, password: Aa123456, schema: DMHR, // 默认模式 entities: [CitySchema, RegionSchema], synchronize: false, // 生产环境必须为 false logging: true, // 打印 SQL 日志 extra: { connectTimeout: 30000, } }; // 【关键点3】创建数据源实例 const AppDataSource new DmdbDataSource(typeormConfig); class TypeormDbService { constructor() { this.logger new Logger(TypeormDbService); this.dataSource null; } async onModuleInit() { try { // 【关键点4】初始化数据源 await AppDataSource.initialize(); this.dataSource AppDataSource; this.logger.log(✅ TypeORM 连接成功); // 测试连接 const cityRepo this.dataSource.getRepository(City); const cityCount await cityRepo.count(); this.logger.log(CITY 表中共有 ${cityCount} 条记录); } catch (error) { this.logger.error(❌ TypeORM 连接失败, error); throw error; } } // 【关键点5】使用 Repository 进行 CRUD async getAllCities() { const cityRepo this.dataSource.getRepository(City); return await cityRepo.find({ order: { CITY_ID: ASC } }); } async createCity(cityData) { const cityRepo this.dataSource.getRepository(City); const newCity cityRepo.create(cityData); return await cityRepo.save(newCity); } async onModuleDestroy() { if (this.dataSource) await this.dataSource.destroy(); } }4.2 流程详解步骤1定义实体EntitySchema 方式name实体名称用于getRepository(City)获取tableName数据库实际表名注意大小写schema数据库模式名达梦区分模式columns字段映射指定数据库字段名与实体属性的对应关系步骤2配置数据源type: oracle达梦兼容 Oracle 协议innerType: dmdb指定使用达梦驱动synchronize: false生产环境必须关闭避免误操作表结构logging: true开启后控制台打印执行的 SQL 语句便于调试步骤3初始化数据源initialize()是异步方法会建立数据库连接只有初始化成功后才能进行后续操作步骤4获取 RepositorygetRepository(City)根据实体名称获取操作对象Repository 提供find、findOne、save、update、delete等方法步骤5CRUD 操作create()创建实体实例不保存到数据库save()保存实体插入或更新find()查询多条记录findOne()查询单条记录update()更新记录delete()删除记录5. 完整代码运行/** * NestJS 连接达梦数据库的两种方式单文件实现 * 操作表DMHR.CITY实际表结构CITY_ID CHAR(3), CITY_NAME VARCHAR(50), REGION_ID INT * 注意REGION_ID 是外键必须存在于 DMHR.REGION 表中 */ const { Injectable, Logger } require(nestjs/common); // 方式一原生驱动连接 const dmdb require(dmdb); class NativeDbService { constructor() { this.logger new Logger(NativeDbService); this.pool null; } async onModuleInit() { try { process.env.NODE_OPTIONS --openssl-legacy-provider; this.pool await dmdb.createPool({ connectionString: dm://SYSDBA:Aa123456localhost:5236/DAMENG?schemaDMHR, poolMax: 10, poolMin: 1, poolTimeout: 60, }); let testConn; try { testConn await this.pool.getConnection(); this.logger.log(✅ 原生驱动连接成功DMHR 模式); } finally { if (testConn) testConn.release(); } } catch (error) { this.logger.error(❌ 原生驱动连接失败, error); throw error; } } async getConnection() { return await this.pool.getConnection(); } async onModuleDestroy() { if (this.pool) await this.pool.close(); } async query(sql, params []) { const conn await this.getConnection(); try { if (params params.length 0) { const result await conn.execute(sql, params); return result; } else { const result await conn.execute(sql); return result; } } finally { conn.release(); } } // 查询 REGION 表获取有效的 REGION_ID async getAllRegions() { const sql SELECT * FROM DMHR.REGION ORDER BY REGION_ID; const result await this.query(sql); if (result result.rows) { const regions result.rows.map(row { const region {}; result.metaData.forEach((col, index) { region[col.name] row[index]; }); return region; }); return regions; } return []; } // CITY 表专用方法 async getAllCities() { const sql SELECT * FROM DMHR.CITY ORDER BY CITY_ID; const result await this.query(sql); if (result result.rows) { const cities result.rows.map(row { const city {}; result.metaData.forEach((col, index) { city[col.name] row[index]; }); return city; }); return cities; } return result; } async getCityById(cityId) { const sql SELECT * FROM DMHR.CITY WHERE CITY_ID ${cityId}; const result await this.query(sql); if (result result.rows result.rows.length 0) { const city {}; result.metaData.forEach((col, index) { city[col.name] result.rows[0][index]; }); return city; } return null; } async getCitiesByRegion(regionId) { const sql SELECT * FROM DMHR.CITY WHERE REGION_ID ${regionId} ORDER BY CITY_ID; const result await this.query(sql); if (result result.rows) { const cities result.rows.map(row { const city {}; result.metaData.forEach((col, index) { city[col.name] row[index]; }); return city; }); return cities; } return []; } async createCity(cityData) { if (cityData.CITY_ID.length 3) { throw new Error(CITY_ID 长度不能超过 3 个字符当前: ${cityData.CITY_ID}); } const sql INSERT INTO DMHR.CITY (CITY_ID, CITY_NAME, REGION_ID) VALUES (${cityData.CITY_ID}, ${cityData.CITY_NAME}, ${cityData.REGION_ID}); const result await this.query(sql); return result; } async updateCity(cityId, cityData) { const sql UPDATE DMHR.CITY SET CITY_NAME ${cityData.CITY_NAME}, REGION_ID ${cityData.REGION_ID} WHERE CITY_ID ${cityId}; const result await this.query(sql); return result; } async deleteCity(cityId) { const sql DELETE FROM DMHR.CITY WHERE CITY_ID ${cityId}; const result await this.query(sql); return result; } } // 方式二TypeORM 整合 const { DmdbDataSource } require(typeorm-dm); const { EntitySchema } require(typeorm); require(reflect-metadata); // 使用 EntitySchema 定义 City 实体 const CitySchema new EntitySchema({ name: City, tableName: CITY, schema: DMHR, columns: { CITY_ID: { primary: true, type: varchar, length: 3, name: CITY_ID }, CITY_NAME: { type: varchar, length: 50, name: CITY_NAME }, REGION_ID: { type: int, name: REGION_ID } } }); // Region 实体用于查询有效的外键值 const RegionSchema new EntitySchema({ name: Region, tableName: REGION, schema: DMHR, columns: { REGION_ID: { primary: true, type: int, name: REGION_ID }, REGION_NAME: { type: varchar, length: 50, name: REGION_NAME } } }); // TypeORM 数据源配置 const typeormConfig { type: oracle, innerType: dmdb, host: localhost, port: 5236, username: SYSDBA, password: Aa123456, schema: DMHR, entities: [CitySchema, RegionSchema], synchronize: false, logging: true, extra: { connectTimeout: 30000, } }; // 创建 TypeORM 数据源实例 const AppDataSource new DmdbDataSource(typeormConfig); // TypeORM 服务封装 class TypeormDbService { constructor() { this.logger new Logger(TypeormDbService); this.dataSource null; } async onModuleInit() { try { await AppDataSource.initialize(); this.dataSource AppDataSource; this.logger.log(✅ TypeORM 连接成功DMHR 模式); const regionRepo this.dataSource.getRepository(Region); const regionCount await regionRepo.count(); this.logger.log(REGION 表中共有 ${regionCount} 条记录); const cityRepo this.dataSource.getRepository(City); const cityCount await cityRepo.count(); this.logger.log(CITY 表中共有 ${cityCount} 条记录); } catch (error) { this.logger.error(❌ TypeORM 连接失败, error); throw error; } } async onModuleDestroy() { if (this.dataSource) await this.dataSource.destroy(); } // CITY 表专用方法 async getAllCities() { const cityRepo this.dataSource.getRepository(City); return await cityRepo.find({ order: { CITY_ID: ASC } }); } async getCityById(cityId) { const cityRepo this.dataSource.getRepository(City); return await cityRepo.findOne({ where: { CITY_ID: cityId } }); } async getCitiesByRegion(regionId) { const cityRepo this.dataSource.getRepository(City); return await cityRepo.find({ where: { REGION_ID: regionId }, order: { CITY_ID: ASC } }); } async createCity(cityData) { if (cityData.CITY_ID.length 3) { throw new Error(CITY_ID 长度不能超过 3 个字符当前: ${cityData.CITY_ID}); } const cityRepo this.dataSource.getRepository(City); const newCity cityRepo.create(cityData); return await cityRepo.save(newCity); } async updateCity(cityId, cityData) { const cityRepo this.dataSource.getRepository(City); await cityRepo.update(cityId, cityData); return await this.getCityById(cityId); } async deleteCity(cityId) { const cityRepo this.dataSource.getRepository(City); const result await cityRepo.delete(cityId); return result.affected 0; } // REGION 表专用方法 async getAllRegions() { const regionRepo this.dataSource.getRepository(Region); return await regionRepo.find({ order: { REGION_ID: ASC } }); } async getRegionById(regionId) { const regionRepo this.dataSource.getRepository(Region); return await regionRepo.findOne({ where: { REGION_ID: regionId } }); } } // 业务服务 class CityService { constructor(nativeDbService, typeormDbService) { this.nativeDbService nativeDbService; this.typeormDbService typeormDbService; this.logger new Logger(CityService); } async queryCitiesWithNative() { try { this.logger.log(使用原生驱动查询所有城市...); const cities await this.nativeDbService.getAllCities(); this.logger.log(原生驱动查询到 ${cities.length} 个城市); return cities; } catch (error) { this.logger.error(原生驱动查询失败, error); throw error; } } async queryCitiesWithTypeorm() { try { this.logger.log(使用 TypeORM 查询所有城市...); const cities await this.typeormDbService.getAllCities(); this.logger.log(TypeORM 查询到 ${cities.length} 个城市); return cities; } catch (error) { this.logger.error(TypeORM 查询失败, error); throw error; } } async getValidRegions() { try { this.logger.log(查询有效的地区列表...); const regions await this.typeormDbService.getAllRegions(); return regions; } catch (error) { this.logger.error(查询地区失败, error); throw error; } } async createCityWithTypeorm(cityData) { try { this.logger.log(使用 TypeORM 创建城市${cityData.CITY_NAME}); const newCity await this.typeormDbService.createCity(cityData); this.logger.log(创建成功ID${newCity.CITY_ID}); return newCity; } catch (error) { this.logger.error(TypeORM 创建城市失败, error); throw error; } } async deleteCityWithTypeorm(cityId) { try { this.logger.log(使用 TypeORM 删除城市 ID: ${cityId}); const success await this.typeormDbService.deleteCity(cityId); this.logger.log(success ? 删除成功 : 删除失败可能不存在); return success; } catch (error) { this.logger.error(TypeORM 删除城市失败, error); throw error; } } } // 测试函数 async function testNativeDriver() { console.log(\n 测试方式一原生驱动DMHR.CITY ); const nativeService new NativeDbService(); try { await nativeService.onModuleInit(); // 0. 先查询有效的 REGION_ID console.log(\n--- 0. 查询有效的地区列表 ---); const regions await nativeService.getAllRegions(); console.log(有效地区, regions); // 使用第一个有效的 REGION_ID const validRegionId regions.length 0 ? regions[0].REGION_ID : 1; console.log(使用地区 ID: ${validRegionId}); // 1. 查询所有城市 console.log(\n--- 1. 查询所有城市 ---); const allCities await nativeService.getAllCities(); console.log(所有城市, allCities); // 2. 根据 ID 查询城市 console.log(\n--- 2. 根据 ID 查询城市 ---); const city await nativeService.getCityById(BJ); console.log(IDBJ 的城市, city); // 3. 根据地区查询城市 console.log(\n--- 3. 根据地区查询城市 ---); const regionCities await nativeService.getCitiesByRegion(validRegionId); console.log(地区 ID${validRegionId} 的城市, regionCities); // 4. 新增测试城市使用有效的 REGION_ID console.log(\n--- 4. 新增测试城市 ---); const testCityId T1; await nativeService.createCity({ CITY_ID: testCityId, CITY_NAME: 测试城市, REGION_ID: validRegionId }); console.log(新增城市成功ID: ${testCityId}); // 5. 查询验证新增 console.log(\n--- 5. 验证新增 ---); const testCity await nativeService.getCityById(testCityId); console.log(新增的城市, testCity); // 6. 删除城市 console.log(\n--- 6. 删除城市 ---); await nativeService.deleteCity(testCityId); console.log(删除成功); // 7. 验证删除 console.log(\n--- 7. 验证删除 ---); const deletedCity await nativeService.getCityById(testCityId); console.log(删除后的查询结果, deletedCity); } catch (error) { console.error(原生驱动测试失败, error); } finally { await nativeService.onModuleDestroy(); } } async function testTypeorm() { console.log(\n 测试方式二TypeORMDMHR.CITY ); const typeormService new TypeormDbService(); try { await typeormService.onModuleInit(); // 0. 获取有效的地区列表 console.log(\n--- 0. 查询有效的地区列表 ---); const regions await typeormService.getAllRegions(); console.log(有效地区, regions); const validRegionId regions.length 0 ? regions[0].REGION_ID : 1; console.log(使用地区 ID: ${validRegionId}); // 1. 查询所有城市 console.log(\n--- 1. 查询所有城市 ---); const allCities await typeormService.getAllCities(); console.log(所有城市, allCities); // 2. 根据 ID 查询城市 console.log(\n--- 2. 根据 ID 查询城市 ---); const city await typeormService.getCityById(BJ); console.log(IDBJ 的城市, city); // 3. 根据地区查询城市 console.log(\n--- 3. 根据地区查询城市 ---); const regionCities await typeormService.getCitiesByRegion(validRegionId); console.log(地区 ID${validRegionId} 的城市, regionCities); // 4. 新增测试城市使用有效的 REGION_ID console.log(\n--- 4. 新增测试城市 ---); const testCityId T2; const newCity await typeormService.createCity({ CITY_ID: testCityId, CITY_NAME: TypeORM测试城市, REGION_ID: validRegionId }); console.log(新增城市, newCity); // 5. 删除城市 console.log(\n--- 5. 删除城市 ---); const deleted await typeormService.deleteCity(testCityId); console.log(deleted ? 删除成功 : 删除失败); // 6. 验证删除 console.log(\n--- 6. 验证删除 ---); const finalCity await typeormService.getCityById(testCityId); console.log(删除后的查询结果, finalCity); } catch (error) { console.error(TypeORM 测试失败, error); } finally { await typeormService.onModuleDestroy(); } } async function testMixedUsage() { console.log(\n 测试混合使用DMHR.CITY ); const nativeService new NativeDbService(); const typeormService new TypeormDbService(); const cityService new CityService(nativeService, typeormService); try { await Promise.all([ nativeService.onModuleInit(), typeormService.onModuleInit() ]); // 0. 获取有效的地区列表 console.log(\n--- 0. 查询有效的地区列表 ---); const regions await cityService.getValidRegions(); console.log(有效地区, regions); const validRegionId regions.length 0 ? regions[0].REGION_ID : 1; console.log(使用地区 ID: ${validRegionId}); // 1. 使用 TypeORM 新增城市使用有效的 REGION_ID console.log(\n--- 1. 使用 TypeORM 新增城市 ---); const testCityId M1; await cityService.createCityWithTypeorm({ CITY_ID: testCityId, CITY_NAME: 混合测试城市, REGION_ID: validRegionId }); // 2. 使用原生驱动查询所有城市 console.log(\n--- 2. 使用原生驱动查询所有城市 ---); const nativeCities await cityService.queryCitiesWithNative(); console.log(原生驱动查询到 ${nativeCities.length} 个城市); // 3. 使用 TypeORM 查询所有城市 console.log(\n--- 3. 使用 TypeORM 查询所有城市 ---); const typeormCities await cityService.queryCitiesWithTypeorm(); console.log(TypeORM 查询到 ${typeormCities.length} 个城市); // 4. 使用 TypeORM 删除城市 console.log(\n--- 4. 使用 TypeORM 删除城市 ---); await cityService.deleteCityWithTypeorm(testCityId); // 5. 验证删除 console.log(\n--- 5. 验证删除 ---); const finalCities await cityService.queryCitiesWithTypeorm(); console.log(最终城市数量${finalCities.length}); } catch (error) { console.error(混合使用测试失败, error); } finally { await Promise.all([ nativeService.onModuleDestroy(), typeormService.onModuleDestroy() ]); } } async function main() { console.log( 达梦数据库连接测试启动); console.log(数据库配置localhost:5236, 用户:SYSDBA, 密码:Aa123456, 模式:DMHR); console.log(操作表DMHR.CITY外键约束REGION_ID 必须存在于 DMHR.REGION 表); const testMode process.argv[2] || all; switch (testMode) { case native: await testNativeDriver(); break; case typeorm: await testTypeorm(); break; case mixed: await testMixedUsage(); break; case all: default: await testNativeDriver(); await testTypeorm(); await testMixedUsage(); break; } console.log(\n✨ 所有测试完成); } if (require.main module) { main().catch(console.error); } module.exports { NativeDbService, TypeormDbService, CityService, typeormConfig, AppDataSource };将完整代码保存为dm-database.js运行测试bash# 运行所有测试 node dm-database.js # 只测试原生驱动 node dm-database.js native # 只测试 TypeORM node dm-database.js typeorm # 测试混合使用 node dm-database.js mixed预期输出text原生方式orm方式6. 常见问题与避坑指南6.1dmdb安装失败错误node-gyp编译失败解决bash# Windows npm install -g windows-build-tools # Ubuntu sudo apt-get install build-essential6.2 Node.js 版本兼容问题错误ERR_OSSL_EVP_UNSUPPORTED解决在代码开头设置环境变量javascriptprocess.env.NODE_OPTIONS --openssl-legacy-provider;6.3 外键约束问题错误违反引用约束[CITY_REG_FK]原因插入的 REGION_ID 在 REGION 表中不存在解决先查询有效的 REGION_IDjavascriptconst regions await nativeService.getAllRegions(); const validRegionId regions[0].REGION_ID;6.4 表名大小写问题达梦数据库对表名大小写敏感SQL 语句中使用大写sqlSELECT * FROM DMHR.CITY -- 正确 SELECT * FROM dmhr.city -- 可能出错6.5 连接池耗尽原因获取连接后没有释放解决使用try/finally确保释放javascriptconst conn await pool.getConnection(); try { await conn.execute(sql); } finally { conn.release(); // 必须执行 }6.6 TypeORM 实体找不到错误No metadata for City was found解决确保实体正确注册到entities数组使用EntitySchema方式定义实体确保name与getRepository参数一致7. 核心总结方案优点缺点推荐场景原生驱动性能好、轻量类型不安全、手动管理高性能、简单查询TypeORM类型安全、开发快性能略低、内存占用高复杂业务、团队协作接入三要素正确安装dmdb驱动配置正确的连接字符串注意 schema 参数处理好外键约束和表名大小写运行命令bash# 安装依赖 npm install dmdb typeorm nestjs/typeorm reflect-metadata typeorm-dm # 运行测试 node dm-database.js附录完整代码文件完整的dm-database.js文件已在上文提供可直接复制保存运行。代码包含原生驱动连接实现NativeDbService 类TypeORM 整合实现TypeormDbService 类业务服务封装CityService 类完整的测试函数三种测试模式导出供其他模块使用的接口

相关文章:

nestjs实战(五): 连接达梦数据库的两种方式(完整实战教程)

还在为 NestJS 项目接入达梦数据库发愁?想用 TypeORM 优雅操作国产数据库,却不知道如何配置?今天这篇教程,全程围绕 NestJS 与达梦数据库的集成展开,从原生驱动连接到 TypeORM 整合,详细解释每一步流程和核…...

单片机/C/C++八股:(十八)C/C++ 中 sizeof 和 strlen 的区别

上一篇下一篇C 中指针和引用的区别C/C 中 sizeof 和 strlen 的区别 本质不同&#xff1a; sizeof&#xff1a;是一个编译时运算符&#xff0c;用于获取 变量或类型所占的字节数&#xff08;包括 \0 &#xff09;。 strlen&#xff1a;是一个函数&#xff08;定义在 <stri…...

单片机/C/C++八股:(十七)C++ 中指针和引用的区别

上一篇下一篇C 中 malloc/free 和 C 中 new/delete 有什么区别&#xff1f;C 中指针和引用的区别 指针&#xff08;Pointer&#xff09;和引用&#xff08;Reference&#xff09;是 C 中两种用于间接访问对象的机制&#xff0c;但它们在本质、行为和使用规则上有根本区别。 本质…...

4μm精度+0.02mm点距:先临三维OptimScan Q12 HD计量级蓝光三维扫描仪为精密测量而生

在精密制造领域&#xff0c;工件几何尺寸的偏差直接影响产品良率&#xff1b;在高端文博领域&#xff0c;高精度三维数据是文物数字化保护与研究的基础。先临三维推出OptimScan Q12 HD计量级蓝光三维扫描仪&#xff0c;以4μm测量精度与细微特征高保真还原为核心优势&#xff0…...

金属+连续纤维+陶瓷3D打印全自主!协同高科30余个高端应用案例展示

协同高科是专注于连续纤维、金属、陶瓷三大材料的综合3D打印解决方案提供商。2026年TCT亚洲展&#xff0c;协同高科发布了多款新设备&#xff0c;并首次展出了30余个高端应用案例。该公司特别指出&#xff0c;基于与众远新材料达成的合作&#xff0c;协同高科已补齐金属材料自主…...

【2026年最新600套毕设项目分享】基于SpringBoot心晴疗愈社平台(14210)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告/任务书&#xff09;远程调试控屏包运行一键启动项目&…...

一篇代码速通 Python 基础语法 | 新手直接上手

这篇文章是我短时间内学习Python基础的总结&#xff0c;个人认为有其他语法基础的同学看了这篇文章可以做到快速上手py语法&#xff0c;不过我相信没有语法基础的同学看了这篇文章也会有所收获。 全文分为 15 个模块&#xff0c;每个知识点独立一段代码 运行结果&#xff0c;…...

Instruct-4DGS: Efficient Dynamic Scene Editing via 4D Gaussian-based Static-Dynamic Separation

4D高斯静态和动态分离实现高效的动态场景编辑一、核心摘要与研究动机核心问题&#xff1a;现有的4D动态场景编辑方法受限于 迭代数据集更新 的范式。如图1(a)所示&#xff0c;它们需要逐帧编辑用于场景合成的成千上万张2D图像&#xff08;T个时间步 M个相机视角&#xff09;&a…...

二分匹配

匹配一、二分图的概念二分图又称作二部图&#xff0c;是图论中的一种特殊模型。设G(V,E)是一个无向图。如顶点集 V 可分割为两个互不相交的子集&#xff0c;并且图中每条边依附的两个顶点都分属两个不同的子集。则称图 G 为二分图。简单解析&#xff1a;也就是设 G ( V,E) 是一…...

蓝牙耳机音质排行榜:全场景音质标准解析与热门机型推荐

在无线音频技术飞速发展的今天&#xff0c;用户对蓝牙耳机的需求早已摆脱了单纯的“听个响”&#xff0c;转而追求更高层次的听觉体验。根据中国电子音响行业协会&#xff08;CAIA&#xff09;的评测标准&#xff0c;音质评价需要结合客观检测与主观听感&#xff0c;涵盖高频、…...

FreeRTOS 锁(信号量)

目录 临界区&#xff08;critical sections&#xff09; 互斥量&#xff08;Mutex&#xff09; 优先级继承性 code示例 递归互斥量 code示例 二值信号量&#xff08;Binary Semaphore&#xff09; 同步功能 code示例 计数信号量&#xff08;Counting Semaphore&#…...

STL---vector详解(从使用到底层)

前言在我的C专栏里有一篇讲解string的文章&#xff0c;里边的各种接口讲解的比较详细&#xff0c;大家对使用有疑惑的可以去我的专栏里看&#xff0c;重复的接口相似的使用我就不再过多介绍了&#xff0c;本文主要讲vector的底层。vector简介vector就是一个会自动扩容的顺序表。…...

【优化升级版】2026在线工具箱源码系统|含字典/成语/查询工具+独立后台管理

温馨提示&#xff1a;文末有联系方式产品核心定位 【优化升级版】2026在线工具箱源码系统&#xff0c;是当前市面上功能最全、稳定性最强的PHP工具聚合平台之一。 本版本由专业团队深度修复并持续迭代&#xff0c;不仅兼容主流建站环境&#xff0c;更强化了SEO结构与蜘蛛抓取友…...

力扣Hot100系列21(Java)——[多维动态规划]总结(不同路径,最小路径和,最长回文子串,最长公共子序列, 编辑距离)

文章目录前言一、不同路径1.题目2.代码3.例子二、最小路径和1.题目2.代码3.例子三、最长回文子串1.题目2.代码3.例子四、最长公共子序列1.题目2.代码3.例子五、 编辑距离1.题目2.代码3.例子前言 本文记录力扣Hot100里面关于多维动态规划的五道题&#xff0c;包括常见解法和一些…...

AI应用架构师助力智能金融系统设计迈向新高度

AI应用架构师&#xff1a;如何重构智能金融系统的“技术基因”&#xff1f; 引言&#xff1a;传统金融系统的“智能焦虑”&#xff0c;你有吗&#xff1f; 凌晨3点&#xff0c;某银行风控部门的张经理还在盯着屏幕——今天又有3笔欺诈交易漏判了。传统的规则引擎已经堆了1000多…...

装修预算装修预算

软装 18000&#xff1a; 沙发 2000 边几 1000 窗帘 5000 餐桌 餐椅 2000 床2 8000 家电 34500&#xff1a; 冰箱 4000 电视机 3000 油烟机灶台热水器 7000 洗碗机 3000 洗衣机 烘干机 4500 扫地机器人 2500 空调3小1大 8000 灯 2500 其他消费3万&#x…...

Ubuntu 22.04外接NVIDIA显卡驱动安装

我的NUC缺一个强大的图形处理硬件, 于是把之前吃灰的显卡坞翻了出来, 发挥点余热, 但是在此之前, 因为开源驱动 nouveau 驱动只能提供基础显示功能&#xff0c;无法调用GPU的加速能力。所以我还需要 彻底禁用nouveau驱动 nouveau是Ubuntu默认的开源驱动&#xff0c;必须禁用&am…...

opencv4.2.0源码安装

git config --global url."https://github.com".insteadOf git://github.comsudo apt update sudo apt upgrade -y# 安装编译工具和依赖库 sudo apt install -y \build-essential \cmake \git \pkg-config \libgtk-3-dev \libavcodec-dev \libavformat-dev \libswsca…...

Ajax Fetch Axios三者的区别

Ajax Fetch Axios三者的区别 三者都用于网路请求&#xff0c;但是不同维度1&#xff0c;Ajax&#xff08;Asynchronous Javascript and XML&#xff09;,一种技术统称2&#xff0c;Fetch&#xff0c;一个具体的API3&#xff0c;Axios&#xff0c;第三方库https&#xff1a;//ax…...

【异常】OpenClaw线上服务器磁盘高位告警故障排查与解决指南 ⚠️ 线上业务节点 磁盘使用率88%(已连续11小时高位运行),建议尽快清理释放空间

一、报错内容 本次故障触发线上服务器监控系统告警,完整告警信息与应急初步处置结果如下: 核心告警条目 ⚠️ 线上业务节点 磁盘使用率88%(已连续11小时高位运行),建议尽快清理释放空间初步应急清理明细 通过临时冗余文件清理,完成首批空间释放,明细如下: 清理项目 预…...

假如后端一次性返回10w条数据,前端如何应对

假如后端一次性返回10w条数据首先设计不合理浏览器能否处理10w条数据1&#xff0c;JS没问题2&#xff0c;渲染到DOM会非常卡顿方案一&#xff1a;自定义中间层&#xff08;1&#xff09;自定义nodejs中间层&#xff0c;获取并拆分这10w条数据&#xff08;2&#xff09;前端对接…...

【异常】OpenClaw 项目 `fetch failed` 报错问题排查与解决方案Response interrupted: TypeError: fetch failed

OpenClaw 项目 fetch failed 报错问题排查与解决方案 一、报错内容 本次问题核心报错原文如下: Response interrupted: TypeError: fetch failedNode.js 运行环境下常见完整报错上下文(已脱敏): node:internal/deps/undici/undici:xxxxError.captureStackTrace(err, t…...

847-便捷视频剪切-视频片段删除合并工具V1.0

对单个视频文件进行剪辑操作&#xff0c;删除视频中的1个片段或多个片段&#xff0c;删除多个片段后自动合并未删除的视频片段&#xff0c;生成的视频为标准H264编码格式的mp4格式视频。 核心功能 视频播放与预览&#xff1a;拖入视频播放预览区间标记&#xff1a;可视化标记需…...

养龙虾-------【openclaw 对接小红书 】---自动化小红书

&#x1f680; MiniMax Token Plan 惊喜上线&#xff01;新增语音、音乐、视频和图片生成权益。邀请好友享双重好礼&#xff0c;助力开发体验&#xff01; 好友立享 9折 专属优惠 Builder 权益&#xff0c;你赢返利 社区特权&#xff01; &#x1f449; 立即参与&#xff1a;…...

告别SQL性能焦虑:教你如何解决

你是否遇到过这样的场景&#xff1a;一个看似复杂的SQL&#xff0c;在测试环境运行飞快&#xff0c;一到生产环境就“卡死”&#xff0c;一查执行计划&#xff0c;发现子查询生成了一个巨大的中间结果集&#xff0c;导致后续操作全部陷入性能泥潭&#xff1f;如果你正被此类场景…...

性能调优实战:数据库连接条件下推原理与案例拆解

文章目录引言一、问题背景1.1 客户场景中的典型痛点1.2 业界普遍面临的两大难点1.2.1 语义安全性&#xff08;Equivalence&#xff09;1.2.2 代价评估&#xff08;Cost&#xff09;二、传统方案的局限三、金仓数据库基于代价的连接条件下推设计3.1 能不能推&#xff1a;等价性判…...

Zed IDE新大招:Git 三合一 Picker,告别“找功能“焦虑症!

推荐阅读 Zed IDE 又整新活&#xff1a;确实比 VS Code 优雅丝滑&#xff01; Zed IDE 又扔出了一个新玩具&#xff0c;确实比 VS Code 清新优雅&#xff01; Zed 推出分栏 Diff &#xff1a;比 VSCode 更快、更智能的Git体验&#xff01; Zed IDE 官宣ACP&#xff1a;一…...

LabVIEW后面板密码移除工具|支持全版本工程|一键清除保护密码

温馨提示&#xff1a;文末有联系方式工具核心功能&#xff1a;全版本LabVIEW后面板密码清除 本工具专为LabVIEW开发环境设计&#xff0c;可安全、稳定地清除LabVIEW VI文件的后面板保护密码。 全面兼容LabVIEW 2010至最新版2024&#xff0c;无论您使用的是32位或64位系统&#…...

告别复杂查询性能噩梦:一文读懂连接条件下推优化

摘要&#xff1a;金仓数据库(KingbaseES)的「基于代价的连接条件下推」技术解决了复杂SQL查询在生产环境中的性能瓶颈问题。该技术通过智能决策框架&#xff0c;先进行安全性检查确保语义等价&#xff0c;再基于代价模型评估下推收益&#xff0c;将连接条件智能下推到子查询中提…...

C语言写量子芯片驱动前必须做的7步接口压力测试:从单光子探测器误触发到多QPU并发访问崩溃的完整复现路径

第一章&#xff1a;C语言量子芯片接口测试的底层约束与物理边界C语言作为量子硬件接口层最广泛采用的系统编程语言&#xff0c;其与量子芯片&#xff08;如超导量子处理器、硅基自旋量子点&#xff09;的交互直接受限于物理层不可逾越的约束&#xff1a;纳秒级时序精度、亚毫伏…...