-

MySQL可以说是互联网企业最为流行的数据库,也是最流行的关系型数据库(云开发数据库是文档型数据库)。如果你的项目已经使用了MySQL,数据库不方便迁移到云开发数据库或者你的业务更偏向于使用MySQL,在这种情况下,也是可以使用连接自建的MySQL数据库并把数据传到小程序端进行渲染的。

一、私有网络VPC

1、公网与私有网络访问数据库的对比

在服务器自建的MySQL或者在腾讯云等云服务公司购买的关系型数据库服务在开放了外部网络连接和IP白名单的情况下,都是可以使用云函数连接的,也就是说云函数是部署在公共网络之中的,只能访问公网的数据库资源(内网或本地的数据库是不行的),而你的数据库要能被公网访问就需要开放外部网络连接和IP白名单。不过云函数目前没有固定的IP,因此数据库需要添加的IP白名单列表会比较长。

如果你不想让数据库暴露在公网环境之下,但是又能被云函数访问,这里推荐使用腾讯云的私有网络。处于私有网络的腾讯云产品(比如云开发的云函数腾讯云的MySQL数据库),可以通过腾讯云提供的对等连接进行互联。对等连接服务相比公网传输有极大的优势

  • 更高质量,与其他腾讯云产品共享同一自建的内部网络,由于是内部传输,不受公网质量影响,可用性、时延、丢包率保障大大提高;

  • 更强安全,内网连接处于腾讯集团级别的防DDos安全防护下,由于不经过广域 Internet 和运营商链路,避免报文在公网传输可能被窃取的风险;

  • 内网传输更快,成本更低,云函数外网流量是要计费的,而同一地域的内网流量则是免费的;

如果你希望云开发的云函数使用图形图像、音视频处理等比较消耗资源的服务,以及对安全有比较高要求的MySQLRedis、TencentDB、Kafka 等服务,我们都建议使用私有网络。

2、私有网络服务的创建

(1)创建上海可用区的私有网络

>腾讯云控制台需要登录时,选择微信公众号(小程序账号属于公众号体系)的登录方式,扫码选择相应的小程序账号进行登录。

打开腾讯云控制台的私有网络免费创建私有网络,由于私有网络具有地域(Region)属性,我们需要在函数所在的地域来新建私有网络。云开发的云函数的服务器部署在上海,因此你的私有网络里的资源也要选择上海。私有网络有三个核心组成成分:私有网络网段IPv4 CIDR、子网和路由表。一个私有网络下的子网可以属于该地域下不同可用区,同一私有网络下各个子网内资源无论是否在同一可用区内,均默认内网互通。而初始子网的可用区,你可以根据你的MySQL等数据库所在的可用区来选,如果你之前在腾讯云没有数据库等,选择上海的任意可用区即可。

(2)在腾讯云购买MySQL并加入同一私有网络

打开腾讯云控制台的MySQL中购买一个实例,创建实例时最主要的是在网络这里找到你之前创建的私有网络以及对应的子网(下拉即可)。

(3)将需要连接MySQL的云函数加入私有网络

打开腾讯云控制台的云开发CloudBase中选择指定的环境,然后点击云函数菜单,然后新建一个云函数或者选择指定的云函数比如mysql,进入配置页面后,点击右上角的“编辑”,在网络配置选择和MySQL服务一样的私有网络。这样云函数就可以通过私有网络的方式连接MySQL了。

然后我们可以根据需要或者结合自身的业务需求,往mysql数据库里导入数据或数据文件,比如可以使用腾讯与自带的DMS往里面导入sql文件。

二、使用mysql2操作MySQL

1、使用mysql2连接MySQL

支持Nodejs连接MySQL数据库的库有很多,比如mysql、mysql2,这里推荐使用mysql2。mysql2是支持async/await的Promise写法的。

使用开发者工具打开之前有的mysql云函数(只要绑定了私有网络即可,没有的话可以参照上一步的说明),在package.json里添加latest最新版的mysql2,并右键云函数目录选择在终端中打开输入命令npm install安装依赖:

  "dependencies": {
    "wx-server-sdk": "latest",
    "mysql2": "latest"
  }

然后在index.js里输入以下代码,这里需要注意的是我们引入的是mysql2/promise,.query的第一个参数是sqlString,也就是SQL命令行语句的字符串格式;当所有数据库请求结束之后,注意要使用.end断开连接,不然云函数会报超时错误。

const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})


const mysql = require('mysql2/promise');
exports.main = async (event, context) => {


  try {
    const connection = await mysql.createConnection({
      host: "10.168.0.7", //内网ip地址
      user: "root",  //数据库的用户名
      password: "tcb123", //数据库密码
      database: "tcb",  //数据库名称
    })


    const [rows, fields] = await connection.query(
      'SELECT * FROM `country` WHERE `country` = "china"',
      );
    connection.end(function(err) {  //注意要断开连接,不然尽管获取到了数据,云函数还是会报超时错误
      console.log('断开连接')
    });
    console.log(rows)
    console.log(fields)
    return rows
  } catch (err) {
    console.log("连接错误", err)
    return err
  }
}

>mysql2模块的很多参数的使用与mysql模块的比较一致,更多配置相关的信息可以查看mysql模块技术文档.

2、mysql2的增删改查

mysql2支持数据库的增删改查,下面只大致列举一些简单的案例,更多的资料可以去查看mysql相关的技术文档:

#创建一个名称为tcb的数据库
CREATE DATABASE `tcb`


#创建一个包含name、address字段的users表格与删除表格
CREATE TABLE `users` (`name` VARCHAR(255), `address` VARCHAR(255))
DROP TABLE `users`


#向users表格里插入记录
INSERT INTO `users`(`name`, `address`) VALUES ('李东bbsky', '深圳')


#查询users表格
SELECT * FROM `users`




#限制查询到的记录数为20,建议记录比较多的数据表查询都需指定limit
SELECT * FROM `users` LIMIT 20


#查询users表格里字段等于某个值的记录
SELECT * FROM `users` WHERE `name` = '李东bbsky'


#将查询结果按名称来排序
SELECT * FROM `users` ORDER BY `name`


#删除满足条件的记录
DELETE FROM `users` WHERE `address` = '深圳'


#更新满足条件的记录的字段值
UPDATE `users` SET `address` = "广州" WHERE `address` = '深圳'


#使用Join进行联表查询
SELECT `users.name` AS `user`, `products.name` AS `favorite` FROM `users` JOIN `products` ON `users.favorite_product` = products.id

3、使用serverless-mysql操作MySQL

下面还推荐一个比较好用的包serverless-mysql,具体使用文档可以参考serverless-mysql技术文档

使用开发者工具打开之前有的mysql云函数,在package.json里添加latest最新版的mysql2,并右键云函数目录选择在终端中打开输入命令npm install安装依赖:

  "dependencies": {
    "wx-server-sdk": "latest",
    "serverless-mysql": "latest"
  }

然后在index.js里输入以下代码,这里需要注意的是我们引入的是mysql2/promise,.query的第一个参数是sqlString,也就是SQL命令行语句的字符串格式;当所有数据库请求结束之后,注意要使用.end断开连接,不然云函数会报超时错误。

const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})
const mysql = require('serverless-mysql')
exports.main = async (event, context) => {
  const connection = await mysql({
    config: {
      host     : "10.168.0.7",//你
      database : "country",
      user     : "root",
      password : "lidongyx327"
    }
  })
  let results = await connection.query('INSERT INTO country(Country, Region) VALUES ("中国","亚洲")')
  await connection.end()
  return results
}

>当然,你还可以使用Sequelize,Sequelize是针对node.js和io.js提供的ORM框架。具体就是突出一个支持广泛,配置和查询方法统一。它支持的数据库包括:PostgreSQL、 MySQL、MariaDB、 SQLite 和 MSSQL。技术文档:Sequelize,这里就不多举例了。

在云函数中使用MySQL,每个云函数在执行时就都会与MySQL的server有连接),但数据库的最大连接数是非常少的(几百几千),我们可以在数据库管理里看到并设置这个值max_connections。由于数据库的连接数比较少,因此建议将数据库的增删改查都写在一个云函数里。这样会减少云函数冷启动的概率以及减少对数据库连接数的占用,而将增删改查的处理集中到一个云函数,我们可以使用到云函数路由tcb-router,后面会有介绍。