操作场景
您可以在云函数中,通过编写代码,快速连接您本地的数据库或者腾讯云云数据库,本文介绍如何使用已有 SDK 在云函数代码中连接 MySQL 云数据库,并实现对数据库的插入、查询等操作。同时还支持已有 SDK 连接 TDSQL-C 或 TDSQL MySQL版 数据库,您可按需进行相应操作。
说明
前提条件
网络环境打通:
对于自建数据库(非腾讯云云数据库),您需要开启公网访问才可以进行连接,否则可能因网络不通导致连接失败。
对于腾讯云云数据库 ,需要保证函数和数据库在同一个 VPC 下。
操作步骤
您可执行以下步骤,开始在云函数代码中连接与管理您的腾讯云云数据库。
创建私有网络 VPC
说明
自建数据库可跳过此步骤。
1. 登录 私有网络控制台。
2. 在顶部选择私有网络所属的地域后,单击**+新建**。
3. 在“新建 VPC ”弹窗中,根据如下信息填入私有网络信息和初始子网名称以及地域。如下图所示:
4. 单击确定即可创建私有网络。
创建数据库实例
说明
自建数据库可跳过此步骤。
1. 登录 TDSQL-C 购买页,选择所要部署的地域、可用区以及数据库规格等信息等,单击立即购买。
2. 购买成功后,返回集群列表,待集群状态显示为“运行中”,即可正常使用。如下图所示:
3. 单击集群 ID,进入集群详情页面。可以对您的数据库集群进行配置修改、账号管理、安全组设置等操作,详情请参见 管理 TDSQL-C 集群。如下图所示:
创建云函数
1. 登录 Serverless 控制台,单击左侧导航栏中的函数服务。
2. 编写您的业务代码,按照正常连接数据库的方式,通过已有 SDK 或者云函数封装的 SCF DB SDK for MySQL 连接数据库,此处以 Node.js 函数为例,更多语言请参考下方 函数代码示例。
说明
exports.main_handler = async (event, context, callback) => {var mysql = require('mysql2');var connection = mysql.createConnection({host : process.env.HOST,user : process.env.USER,password : process.env.PASSWORD});connection.connect();connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {if (error) throw error;console.log('The solution is: ', results[0].solution);});connection.end();}
3. 进入该函数的“函数配置”页面,参考以下信息进行配置。
1. 新增环境变量,并参考以下表格填写。如下图所示:
key | value |
HOST | 数据库地址 |
USER | 数据库用户名 |
PASSWORD | 数据库密码 |
2. 开启私有网络,并选择和数据库相同的私有网络和子网。如下图所示:
3. 完成配置后保存,调用您的函数,即可连接与管理您的数据库。
函数代码示例
Python 可使用云函数环境已经内置的 pymysql 依赖包进行数据库连接。示例代码如下:
# -*- coding: utf8 -*-from os import getenvimport pymysqlfrom pymysql.err import OperationalErrormysql_conn = Nonedef __get_cursor():try:return mysql_conn.cursor()except OperationalError:mysql_conn.ping(reconnect=True)return mysql_conn.cursor()def main_handler(event, context):global mysql_connif not mysql_conn:mysql_conn = pymysql.connect(host = getenv('DB_HOST', '<YOUR DB HOST>'),user = getenv('DB_USER','<YOUR DB USER>'),password = getenv('DB_PASSWORD','<YOUR DB PASSWORD>'),db = getenv('DB_DATABASE','<YOUR DB DATABASE>'),port = int(getenv('DB_PORT','<YOUR DB PORT>')),charset = 'utf8mb4',autocommit = True)with __get_cursor() as cursor:cursor.execute('select * from employee')myresult = cursor.fetchall()print(myresult)for x in myresult:print(x)
Node.js 支持使用连接池进行连接,连接池具备自动重连功能,可有效避免因云函数底层或者数据库释放连接造成的连接不可用情况。示例代码如下:
说明
'use strict';const DB_HOST = process.env[`DB_HOST`]const DB_PORT = process.env[`DB_PORT`]const DB_DATABASE = process.env[`DB_DATABASE`]const DB_USER = process.env[`DB_USER`]const DB_PASSWORD = process.env[`DB_PASSWORD`]const promisePool = require('mysql2').createPool({host : DB_HOST,user : DB_USER,port : DB_PORT,password : DB_PASSWORD,database : DB_DATABASE,connectionLimit : 1}).promise();exports.main_handler = async (event, context, callback) => {let result = await promisePool.query('select * from employee');console.log(result);}
PHP 可使用 pdo_mysql 或 mysqli 依赖包进行数据连接。示例代码如下:
<?phpfunction handler($event, $context) {try{$pdo = new PDO('mysql:host= getenv("DB_HOST");dbname= getenv("DB_DATABASE"),getenv("DB_USER"),getenv("DB_PASSWORD")');$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);}catch(PDOException $e){echo '数据库连接失败: '.$e->getMessage();exit;}}
<?phpfunction main_handler($event, $context) {$host = "";$username = "";$password = "";// 创建连接$conn = mysqli_connect($servername, $username, $password);// 检测连接if (!$conn) {die("Connection failed: " . mysqli_connect_error());}echo "连接成功";mysqli_close($conn);echo "断开连接";}?>
<dependencies><dependency><groupId>com.tencentcloudapi</groupId><artifactId>scf-java-events</artifactId><version>0.0.2</version></dependency><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>3.2.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.11</version></dependency></dependencies>
使用 Hikari 连接池进行连接,示例代码如下:
package example;import com.qcloud.scf.runtime.Context;import com.qcloud.services.scf.runtime.events.APIGatewayProxyRequestEvent;import com.qcloud.services.scf.runtime.events.APIGatewayProxyResponseEvent;import com.zaxxer.hikari.HikariConfig;import com.zaxxer.hikari.HikariDataSource;import javax.sql.DataSource;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.HashMap;import java.util.Map;public class Http {private DataSource dataSource;public Http() {HikariConfig config = new HikariConfig();config.setJdbcUrl("jdbc:mysql://" + System.getenv("DB_HOST") + ":"+ System.getenv("DB_PORT") + "/" + System.getenv("DB_DATABASE"));config.setUsername(System.getenv("DB_USER"));config.setPassword(System.getenv("DB_PASSWORD"));config.setDriverClassName("com.mysql.jdbc.Driver");config.setMaximumPoolSize(1);dataSource = new HikariDataSource(config);}public String mainHandler(APIGatewayProxyRequestEvent requestEvent, Context context) {System.out.println("start main handler");System.out.println("requestEvent: " + requestEvent);System.out.println("context: " + context);try (Connection conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement("SELECT * FROM employee")) {ResultSet rs = ps.executeQuery();while (rs.next()) {System.out.println(rs.getInt("id"));System.out.println(rs.getString("first_name"));System.out.println(rs.getString("last_name"));System.out.println(rs.getString("address"));System.out.println(rs.getString("city"));}} catch (SQLException e) {e.printStackTrace();}APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent = new APIGatewayProxyResponseEvent();apiGatewayProxyResponseEvent.setBody("API GW Test Success");apiGatewayProxyResponseEvent.setIsBase64Encoded(false);apiGatewayProxyResponseEvent.setStatusCode(200);Map<String, String> headers = new HashMap<>();headers.put("Content-Type", "text");headers.put("Access-Control-Allow-Origin", "*");apiGatewayProxyResponseEvent.setHeaders(headers);return apiGatewayProxyResponseEvent.toString();}}
SCF DB SDK for MySQL
为方便使用,云函数团队将 Node.js 和 Python 连接池相关代码封装为 SCF DB SDK for MySQL,通过该 SDK,您可以在云函数代码中连接 MySQL、TDSQL-C 或 TDSQL MySQL版 数据库,并实现对数据库的插入、查询等操作。
SCF DB SDK for MySQL 具备以下特点:
自动从环境变量初始化数据库客户端。
SDK 会在全局维护一个数据库长连接,并处理连接中断后的重连。
云函数团队会持续关注 issue,确保获得连接即可用,不需要关注数据库连接。
示例代码如下:
'use strict';const database = require('scf-nodejs-serverlessdb-sdk').database;exports.main_handler = async (event, context, callback) => {let pool = await database('TESTDB2').pool()pool.query('select * from coffee',(err,results)=>{console.log('db2 callback query result:',results)})// no need to release poolconsole.log('db2 query result:',result)}
from serverless_db_sdk import databasedef main_handler(event, context):print('Start Serverlsess DB SDK function')connection = database().connection(autocommit=False)cursor = connection.cursor()cursor.execute('SELECT * FROM name')myresult = cursor.fetchall()for x in myresult:print(x)
说明
1. Python3.6、Python2.7、Node.js12.16、Node.js10.15已经内置了 SCF DB SDK for MySQL,无需额外安装。
2. 其他 Node.js 版本可参考 依赖安装 安装
scf-nodejs-serverlessdb-sdk
进行使用。3. Node.js SDK 具体使用方法请参见 SCF DB SDK for MySQL。
常见问题
在云函数 SCF 的运行机制下如何更加高效的管理数据库连接?
SCF 的每个请求实际运行在一个容器上,容器在有连续请求的场景下可在一段时间内复用。数据库的连接创建建议在初始化容器的时候进行,即对应函数代码的全局部分。数据库连接建立后,在容器存在的时间段内均可以进行复用,在容器释放时会断开。避免在入口函数内部频繁进行数据库的连接和关闭,影响性能。为保证数据库的连接可用,可在入口函数内部进行连接检查。
建议使用数据库连接池进行容器数据库连接管理,最小连接数设置为1即可。
在函数高并发场景下如何进行数据库连接管理?
函数高并发场景下,并发数可能超过数据库最大连接数,可以参考如下方案进行处理:
增大数据库最大连接数。
设置函数最大独占并发配额,限制函数的并发数小于数据库最大连接数。
云数据库 MySQL 提供 数据库代理功能,通过代理集群中转访问数据库的主从节点,进行读写分离,将读请求转发至只读实例,降低主库的负载。