告别回调地狱,在Node里优雅的访问MySQL(二)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Node.js 环境里面访问 MySQL 的默认方式,采用了古老的回调方式,这样很容易产生回调地狱。那么如何避免呢?这里介绍一种基于 Promise 的封装方式,可以避免回调地狱,并且支持事务访问。

await 方式

我们是否可以用 await 的方式实现一下开启事务的代码呢?尝试了一下,也是可以的,虽然这么做没有什么实际意义。


/**
* 开启事务,await 的方式
*/
async beginTransaction() {
console.log('★ 开启事务,await 模式')
let _cn = null
try {
_cn = awaitthis._poolCreateConnection()
awaitthis._beginStran(_cn)
} catch(e) {
console.log('async 开启事务出错:', e)
}
return _cn
}


没有了回调方式,看起来是不是舒服多了?为啥说没啥实际意义呢?因为这种方式,要求调用者也必须使用 await 的方式,有点强制性。而上面那个函数(begin)既可以用 Promise 的方式,也可以用 await 的方式,即满足需求也比较灵活。


提交事务

开启事务,执行各种操作后,需要提交事务,那么我们再做一个提交事务的功能。


/**
* 提交一个事务
* @param { connection } cn 开启事务时创建的连接对象
*/
commit(_cn) {
const myPromise = newPromise((resolve, reject) => {
// 提交事务
_cn.commit((err) => {
if(err) {
console.log('事务提交失败', err)
reject(err)
} else {
resolve()
}
})
})
return myPromise
}


关闭连接、归还连接对象

如果没有开始事务,直接关闭连接即可,如果开启事务,需要把链接对象放回池子。二者写法有点差别。

/**
* 关闭数据库
* @param { connection } cn 开启事务时创建的连接对象
*/
close(_cn = null) {
if (_cn !== null ) {
// 归还连接对象。
_cn.release()
} else {
// 关闭连接
this.db.end((err) => {
if(err) {
console.error('关闭连接发生错误:', err)
} else {
console.log('\n[MySQL 已经关闭数据库:]\n')
}
})
}
}


关闭连接池

如果开启事务的话,还需要关闭连接池。

/**
* 关闭池子
*/
closePool() {
this.pool.end((err) => {
if(err) {
console.error('关闭连接发生错误:', err)
} else {
console.log('\n[MySQL 已经关闭连接池:]\n')
}
})
}

封装SQL语句


核心操作,上面的 help 就可以实现了,下面要封装SQL,避免手撸SQL的尴尬。思路有点像ORM,但是又不完全是ORM,采用 meta + model 的形式拼接参数化的SQL语句。

insert —— addModel

从SQL语句的角度来看,是 insert into table,从对象的角度来看,就是添加了一个model。不管怎么说,都是需要一个SQL语句才行,如果手撸的话,既麻烦又容易出错,那么怎么办呢?我们可以先设定一个 meta 进行描述,然后写个函数拼接即可。

  • meta
{
"tableName": "node_user",
"idKey": "id",
"cols": {
"name": "",
"age": ""
} 
}


由表名、主键字段名、需要的字段集合组成,这个看起来好像是一个表、字段的结构,其实并不是,区别在于字段集合的组成方式。

一般情况是基于表建立的 model,需要把表的字段都加上,不能少。

但是这里的 meta 并不要求把表里面的字段都加上,而是根据业务需求设置字段,业务需要哪些字段就放置哪些字段,不需要的可以不放。

另外一个表可以设置多种这样的 meta,完全依据业务需求来决定。

  • 实现代码

/data-add.js

/**
* 实现添加数据的功能。拼接 insert 的 SQL语句
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { Object } model 数据
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName:'', 表名
* * * cols:{colName: '类型'}, josn 字段需要标记 
* * model 结构:
* * * colName: value 
*/
function addData(help, meta, model, cn = null) {
// 拼接添加用的SQL语句,
// 提交SQL语句
const myPromise = newPromise((resolve, reject) => {
// sql = 'INSERT INTO aaa set aaacol = ? '
// 获取字段名称和值的数组
const { colNames, params } = help.createTableCols(meta, model)
const sql = `INSERT INTO ${meta.tableName} SET ${colNames.join(',')} `
console.log('addData --- sql:', sql, params)
const _cn = cn === null ? help.db : cn
help.query(sql, params, _cn)
.then((res) => {
// console.log('添加数据成功:', res.insertId)
resolve(res.insertId)
})
.catch((res) => {
// 出错了
reject(res)
})
})
return myPromise
}
module.exports = addData

如果使用事务的话,需要传递一个链接对象进来,否则使用内部默认的连接对象。

  • help  实现基础功能的实例。
  • meta  上面说到的表、字段的描述
  • model  要添加的数据


update

同上(代码雷同就不贴了),拼接 update 的SQL语句,加上where即可。

每一个小功能都做成了独立的 js 文件。其实一开始想做一个大的class,后来觉得代码太长不好维护,于是想做成子类的形式,但是想想似乎没啥必要,除了少传递一个help参数之外好像没啥区别。所以最后决定采用这种方式,


delete

同上,只需要表名和主键字段即可。


/**
* 实现删除数据的功能。拼接 DELETE FROM 的 SQL语句
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } info 表、字段
* @param { number|string } id 数据
* @returns 影响的记录数
* * info 结构:
* * * tableName:'', 表名
* * * idKey '', 主键名称
* * * cols:{colName: '类型'}, josn 字段需要标记 
* * id :number | string
*/
function deleteData(help, info, id, cn = null) {
// 拼接 修改 用的SQL语句,
const myPromise = newPromise((resolve, reject) => {
const sql = `DELETE FROM ${info.tableName} WHERE ${info.idKey} = ? `
const _cn = cn === null ? help.db : cn
help.query(sql, [id], _cn)
.then((res) => {
// 删除成功,返回影响行数
resolve(res.affectedRows)
})
.catch((res) => {
// 出错了
reject(res)
})
})
return myPromise
}
module.exports = deleteData
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
6
分享
相关文章
Docker安装Mysql5.7,解决无法访问DockerHub问题
当 Docker Hub 无法访问时,可以通过配置国内镜像加速来解决应用安装失败和镜像拉取超时的问题。本文介绍了如何在 CentOS 上一键配置国内镜像加速,并成功拉取 MySQL 5.7 镜像。
1070 3
Docker安装Mysql5.7,解决无法访问DockerHub问题
node博客小项目:接口开发、连接mysql数据库
【10月更文挑战第14天】node博客小项目:接口开发、连接mysql数据库
Node服务连接Mysql数据库
本文介绍了如何在Node服务中连接MySQL数据库,并实现心跳包连接机制。
73 0
Node服务连接Mysql数据库
Node.js 连接 MySQL
10月更文挑战第9天
73 0
node连接mysql,并实现增删改查功能
【8月更文挑战第26天】node连接mysql,并实现增删改查功能
198 3
【Azure 应用服务】NodeJS项目部署在App Service For Linux环境中,部署完成后应用无法访问
【Azure 应用服务】NodeJS项目部署在App Service For Linux环境中,部署完成后应用无法访问
揭秘Node.js如何轻松访问API:一个示例足以改变你的开发视角!
【8月更文挑战第21天】在现代Web开发中,API是软件间通信的关键。Node.js以其高效性,在API访问上独具优势。本文通过示例展示如何用Node.js访问API。首先确保已安装Node.js,然后使用npm安装`axios`库。创建`api_example.js`文件,并编写代码以访问JSONPlaceholder API获取数据。成功时,响应数据会输出至控制台;若失败,则打印错误。此示例展示了Node.js结合`axios`访问API的便捷性及高效性,为初学者提供快速入门指南。
63 0
Docker Compose V2 安装常用数据库MySQL+Mongo
以上内容涵盖了使用 Docker Compose 安装和管理 MySQL 和 MongoDB 的详细步骤,希望对您有所帮助。
157 42
如何排查和解决PHP连接数据库MYSQL失败写锁的问题
通过本文的介绍,您可以系统地了解如何排查和解决PHP连接MySQL数据库失败及写锁问题。通过检查配置、确保服务启动、调整防火墙设置和用户权限,以及识别和解决长时间运行的事务和死锁问题,可以有效地保障应用的稳定运行。
106 25

热门文章

最新文章

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等