ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Node.js 连接 SQL Server 实战:mssql 模块封装与避坑指南

Node.js 连接 SQL Server 实战:mssql 模块封装与避坑指南 简介这份资源面向具备一定 Node.js 基础的开发者聚焦于使用 mssql 模块连接 SQL Server 数据库的封装实践帮助读者解决数据库连接代码重复、复用性差的问题。资源包内含 1 个 docx 文档大小约 16KB以图文与代码片段结合的方式呈现便于边看边练。文档围绕 mssql 模块的安装、连接配置、PreparedStatement 执行 SQL 及连接池参数设置展开并给出 db.js 封装与调用示例读者可据此快速搭建可复用的数据库访问层。内容还提示了开启 SQL Server 远程连接、调整防火墙入站规则等常见排错要点适合作为 Node.js 后端开发者的参考资料。目前已有 833 人学习可作为入门 mssql 封装与后续扩展的起点。1. 从一份 docx 说起Node.js 连 SQL Server 到底难在哪很多人第一次用 Node.js 接 SQL Server卡住的地方往往不是 SQL 本身而是环境。SQL Server 默认不开 TCP/IP、1433 端口被防火墙挡着、encrypt选项在本地和云上行为不一致随便一个都能让你对着ConnectionError: Failed to connect to localhost:1433发呆半天。这份 docx 给的是一个极简的mssql模块封装一个db.js管连接配置暴露一个db.sql(sql, callback)方法调用方只管传 SQL 和回调。它不花哨但把「配置、连接、预编译、执行、释放」这条链路完整走了一遍适合两类人一是刚上手 Node.js 又要对接 SQL Server 的后端新手二是手里有老 SQL Server 库、想用脚本快速做查询和运维的工程师。下面我按「能跑起来 → 能改对 → 不踩坑」的顺序把它拆开。2. 环境先打通mssql 模块安装与 SQL Server 远程连接配置2.1 安装 mssql 与确认 Node 环境mssql是 Tedious 驱动之上的一层封装纯 JS 实现不依赖 ODBC所以在 Windows、Linux、macOS 上装法一致。先确认 Node 版本mssql6.x 以上要求 Node 10现在主流 LTS 都没问题。node -v npm -v npm install mssql如果你在 PowerShell 里执行npm报「无法加载文件 npm.ps1因为在此系统上禁止运行脚本」这不是 mssql 的问题是 PowerShell 执行策略拦的。常见做法是改用 CMD 执行或者以管理员身份运行Set-ExecutionPolicy RemoteSigned后重开终端。装完在package.json的dependencies里能看到mssql条目说明模块到位。2.2 SQL Server 侧必须打开的三件事Node 连不上九成出在服务端没放行。按顺序检查打开 SQL Server 配置管理器在「SQL Server 网络配置 → 实例的协议」里把TCP/IP状态改为「已启用」。双击 TCP/IP在「IP 地址」页拉到最底部IPAll把 TCP 端口设为1433TCP 动态端口留空。重启 SQL Server 服务然后在 Windows 防火墙入站规则里放行 1433 端口或者临时关闭入站拦截做连通性验证。验证是否真的通了不用写代码先在命令行探一下端口# Windows telnet 10.81.36.167 1433 # Linux / macOS nc -vz 10.81.36.167 1433能连上会显示连接成功连不上就是网络层没放行此时改 Node 代码没有任何意义。另外确认登录账号示例里用的是sa已启用 SQL Server 身份验证模式而不是仅 Windows 身份验证。提示生产环境不要用sa跑应用建一个只有目标库读写权限的独立账号权限最小化。3. 封装 db.js连接配置、PreparedStatement 与连接池参数3.1 config 对象里每个字段的含义原示例的配置长这样我逐字段说明因为改错一个就连不上var mssql require(mssql); var db {}; var config { user: sa, // 登录账号 password: 123456, // 登录密码 server: 10.81.36.167, // 服务器 IP 或主机名不要带端口 database: admanager, // 默认连接的库 port: 1433, // 端口单独写别拼进 server options: { encrypt: true // 云上/Azure 必须 true本地实例视配置而定 }, pool: { min: 0, // 池中保持的最小连接数 max: 10, // 池中允许的最大连接数 idleTimeoutMillis: 3000 // 空闲连接超过 3 秒被回收 } };server和port要分开写把10.81.36.167:1433塞进server是新手最常见的翻车点。encrypt在本地老实例上如果报证书相关错误可以先设为false验证云数据库则保持true。pool.max不是越大越好SQL Server 单实例连接数有限10 到 20 对中小应用足够盲目调到几百反而会拖垮数据库。3.2 db.sql 的执行链路拆解封装的核心是一个方法把「建连接 → 预编译 → 执行 → 释放」串起来db.sql function (sql, callBack) { var connection new mssql.Connection(config, function (err) { if (err) { console.log(err); return; } var ps new mssql.PreparedStatement(connection); ps.prepare(sql, function (err) { if (err) { console.log(err); return; } ps.execute(, function (err, result) { if (err) { console.log(err); return; } ps.unprepare(function (err) { if (err) { console.log(err); callBack(err, null); return; } callBack(err, result); }); }); }); }); }; module.exports db;逻辑说明new mssql.Connection建立连接PreparedStatement把 SQL 预编译execute执行unprepare释放语句句柄最后回调把result交给调用方。参数说明ps.execute(, ...)的第一个参数是参数化占位符这里传空字符串表示没有绑定参数纯 SQL 查询。result里除了数据行还带rowsAffected、recordset等字段取行数用result.recordset.length更稳妥。注意原封装在err分支里只console.log没有回调调用方会一直等不到响应。生产代码里每个错误分支都要callBack(err, null)否则就是黑匣子。3.3 连接池的正确用法原示例虽然配了pool但每次调用都new mssql.Connection等于每次新建连接池根本没复用。正确做法是用mssql.connect建全局连接池之后用mssql.Request复用var poolPromise mssql.connect(config); db.sql function (sql, params, callBack) { poolPromise.then(function (pool) { var request pool.request(); // 绑定参数防注入 if (params) { Object.keys(params).forEach(function (k) { request.input(k, params[k]); }); } return request.query(sql); }).then(function (result) { callBack(null, result); }).catch(function (err) { callBack(err, null); }); };这样连接在进程生命周期内复用pool.max才真正生效。调用时用name占位db.sql(select * from XRuserSet where id id, { id: 1 }, function (err, result) { if (err) { console.log(err); return; } console.log(用户总数为, result.recordset.length); });参数化查询是防 SQL 注入的基本功字符串拼接 SQL 在带用户输入的场景里迟早出事。4. 避坑与排查连不上、查不出、结果对不上的五类问题4.1 连接超时 ConnectionError现象报Failed to connect to 10.81.36.167:1433或超时。原因TCP/IP 没启用、端口没放行、server字段拼了端口。解决按 2.2 的三步逐项确认用telnet/nc先验证端口再回头查代码。4.2 登录失败 Login failed for user现象Login failed for user sa。原因账号密码错、SQL Server 只开了 Windows 身份验证、账号被禁用。解决在 SSMS 里用同一账号密码手动登录验证确认实例是「混合验证模式」必要时在安全性里启用并重置密码。4.3 encrypt 导致的证书错误现象self signed certificate或 TLS 相关报错。原因本地实例没配受信任证书而encrypt: true强制加密。解决本地开发可临时设encrypt: false或加trustServerCertificate: true云上保持encrypt: true并配置正确证书。4.4 回调不触发、进程挂住现象调用db.sql后既没结果也没报错程序卡死。原因错误分支只console.log没回调或连接没释放。解决所有分支补callBack用pool.close()在进程退出时释放连接池。4.5 结果取错字段现象result.length是undefined。原因mssql返回的是结果对象不是数组。解决用result.recordset.length取行数result.rowsAffected取影响行数别直接对result取length。5. 进阶把封装改成 Promise 并加一层查询日志回调写法在多层嵌套时很难维护我一般会把db.sql再包一层 Promise同时加一个耗时日志方便排查慢查询。这样既保留原封装的简单又能接async/awaitdb.query function (sql, params) { var start Date.now(); return new Promise(function (resolve, reject) { db.sql(sql, params, function (err, result) { var cost Date.now() - start; // 超过 500ms 打日志方便定位慢 SQL if (cost 500) { console.log([slow sql], cost ms, sql); } if (err) { reject(err); return; } resolve(result); }); }); }; // 调用 async function main() { try { var result await db.query(select * from XRuserSet); console.log(用户总数为, result.recordset.length); } catch (e) { console.log(查询失败, e.message); } } main();参数说明params是{ 占位符名: 值 }的对象db.sql内部用request.input绑定cost是毫秒耗时阈值按业务调报表类查询可以放宽到 2000ms。验证方法很简单故意写一条全表扫描的 SQL看日志有没有打出来再对比 SSMS 里的执行时间两边差太多说明网络或连接池有问题。几个边界要清楚mssql的recordset对超大结果集会一次性载入内存几十万行以上要改用流式request.stream事务场景不能直接用这个封装得用new mssql.Transaction手动begin/commit/rollback连接池在serverless环境里要设pool.min: 0并配合idleTimeoutMillis否则空闲连接会被平台回收导致下次请求报错。从那以后我每次接新库都强制先跑一遍telnet探端口、再用最小账号连一次、最后才写业务 SQL这三步省下的排查时间比什么都值。希望帮到你。本文还有配套的精品资源点击获取
返回列表