使用 Lambda 函数连接到 Amazon RDS 数据库 - Amazon Relational Database Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

使用 Lambda 函数连接到 Amazon RDS 数据库

以下代码示例显示如何实现连接到 RDS 数据库的 Lambda 函数。该函数发出一个简单的数据库请求并返回结果。

Go
适用于 Go V2 的 SDK
注意

查看 GitHub,了解更多信息。在无服务器示例存储库中查找完整示例,并了解如何进行设置和运行。

在 Lambda 函数中使用 Go 连接到 Amazon RDS 数据库。

/* Golang v2 code here. */ package main import ( "context" "database/sql" "encoding/json" "fmt" "os" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/feature/rds/auth" _ "github.com/go-sql-driver/mysql" ) type MyEvent struct { Name string `json:"name"` } func HandleRequest(event *MyEvent) (map[string]interface{}, error) { var dbName string = os.Getenv("DatabaseName") var dbUser string = os.Getenv("DatabaseUser") var dbHost string = os.Getenv("DBHost") // Add hostname without https var dbPort int = os.Getenv("Port") // Add port number var dbEndpoint string = fmt.Sprintf("%s:%d", dbHost, dbPort) var region string = os.Getenv("AWS_REGION") cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { panic("configuration error: " + err.Error()) } authenticationToken, err := auth.BuildAuthToken( context.TODO(), dbEndpoint, region, dbUser, cfg.Credentials) if err != nil { panic("failed to create authentication token: " + err.Error()) } dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true&allowCleartextPasswords=true", dbUser, authenticationToken, dbEndpoint, dbName, ) db, err := sql.Open("mysql", dsn) if err != nil { panic(err) } defer db.Close() var sum int err = db.QueryRow("SELECT ?+? AS sum", 3, 2).Scan(&sum) if err != nil { panic(err) } s := fmt.Sprint(sum) message := fmt.Sprintf("The selected sum is: %s", s) messageBytes, err := json.Marshal(message) if err != nil { return nil, err } messageString := string(messageBytes) return map[string]interface{}{ "statusCode": 200, "headers": map[string]string{"Content-Type": "application/json"}, "body": messageString, }, nil } func main() { lambda.Start(HandleRequest) }
Java
SDK for Java 2.x
注意

查看 GitHub,了解更多信息。在无服务器示例存储库中查找完整示例,并了解如何进行设置和运行。

在 Lambda 函数中使用 Java 连接到 Amazon RDS 数据库。

import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rdsdata.RdsDataClient; import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementRequest; import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementResponse; import software.amazon.awssdk.services.rdsdata.model.Field; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; public class RdsLambdaHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> { @Override public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) { APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); try { // Obtain auth token String token = createAuthToken(); // Define connection configuration String connectionString = String.format("jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true", System.getenv("ProxyHostName"), System.getenv("Port"), System.getenv("DBName")); // Establish a connection to the database try (Connection connection = DriverManager.getConnection(connectionString, System.getenv("DBUserName"), token); PreparedStatement statement = connection.prepareStatement("SELECT ? + ? AS sum")) { statement.setInt(1, 3); statement.setInt(2, 2); try (ResultSet resultSet = statement.executeQuery()) { if (resultSet.next()) { int sum = resultSet.getInt("sum"); response.setStatusCode(200); response.setBody("The selected sum is: " + sum); } } } } catch (Exception e) { response.setStatusCode(500); response.setBody("Error: " + e.getMessage()); } return response; } private String createAuthToken() { // Create RDS Data Service client RdsDataClient rdsDataClient = RdsDataClient.builder() .region(Region.of(System.getenv("AWS_REGION"))) .credentialsProvider(DefaultCredentialsProvider.create()) .build(); // Define authentication request ExecuteStatementRequest request = ExecuteStatementRequest.builder() .resourceArn(System.getenv("ProxyHostName")) .secretArn(System.getenv("DBUserName")) .database(System.getenv("DBName")) .sql("SELECT 'RDS IAM Authentication'") .build(); // Execute request and obtain authentication token ExecuteStatementResponse response = rdsDataClient.executeStatement(request); Field tokenField = response.records().get(0).get(0); return tokenField.stringValue(); } }
JavaScript
适用于 JavaScript 的 SDK(v3)
注意

查看 GitHub,了解更多信息。在无服务器示例存储库中查找完整示例,并了解如何进行设置和运行。

在 Lambda 函数中使用 JavaScript 连接到 Amazon RDS 数据库。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 /* Node.js code here. */ // ES6+ example import { Signer } from "@aws-sdk/rds-signer"; import mysql from 'mysql2/promise'; async function createAuthToken() { // Define connection authentication parameters const dbinfo = { hostname: process.env.ProxyHostName, port: process.env.Port, username: process.env.DBUserName, region: process.env.AWS_REGION, } // Create RDS Signer object const signer = new Signer(dbinfo); // Request authorization token from RDS, specifying the username const token = await signer.getAuthToken(); return token; } async function dbOps() { // Obtain auth token const token = await createAuthToken(); // Define connection configuration let connectionConfig = { host: process.env.ProxyHostName, user: process.env.DBUserName, password: token, database: process.env.DBName, ssl: 'Amazon RDS' } // Create the connection to the DB const conn = await mysql.createConnection(connectionConfig); // Obtain the result of the query const [res,] = await conn.execute('select ?+? as sum', [3, 2]); return res; } export const handler = async (event) => { // Execute database flow const result = await dbOps(); // Return result return { statusCode: 200, body: JSON.stringify("The selected sum is: " + result[0].sum) } };

在 Lambda 函数中使用 TypeScript 连接到 Amazon RDS 数据库。

import { Signer } from "@aws-sdk/rds-signer"; import mysql from 'mysql2/promise'; // RDS settings // Using '!' (non-null assertion operator) to tell the TypeScript compiler that the DB settings are not null or undefined, const proxy_host_name = process.env.PROXY_HOST_NAME! const port = parseInt(process.env.PORT!) const db_name = process.env.DB_NAME! const db_user_name = process.env.DB_USER_NAME! const aws_region = process.env.AWS_REGION! async function createAuthToken(): Promise<string> { // Create RDS Signer object const signer = new Signer({ hostname: proxy_host_name, port: port, region: aws_region, username: db_user_name }); // Request authorization token from RDS, specifying the username const token = await signer.getAuthToken(); return token; } async function dbOps(): Promise<mysql.QueryResult | undefined> { try { // Obtain auth token const token = await createAuthToken(); const conn = await mysql.createConnection({ host: proxy_host_name, user: db_user_name, password: token, database: db_name, ssl: 'Amazon RDS' // Ensure you have the CA bundle for SSL connection }); const [rows, fields] = await conn.execute('SELECT ? + ? AS sum', [3, 2]); console.log('result:', rows); return rows; } catch (err) { console.log(err); } } export const lambdaHandler = async (event: any): Promise<{ statusCode: number; body: string }> => { // Execute database flow const result = await dbOps(); // Return error is result is undefined if (result == undefined) return { statusCode: 500, body: JSON.stringify(`Error with connection to DB host`) } // Return result return { statusCode: 200, body: JSON.stringify(`The selected sum is: ${result[0].sum}`) }; };
PHP
适用于 PHP 的 SDK
注意

查看 GitHub,了解更多信息。在无服务器示例存储库中查找完整示例,并了解如何进行设置和运行。

在 Lambda 函数中使用 PHP 连接到 Amazon RDS 数据库。

<?php # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 # using bref/bref and bref/logger for simplicity use Bref\Context\Context; use Bref\Event\Handler as StdHandler; use Bref\Logger\StderrLogger; use Aws\Rds\AuthTokenGenerator; use Aws\Credentials\CredentialProvider; require __DIR__ . '/vendor/autoload.php'; class Handler implements StdHandler { private StderrLogger $logger; public function __construct(StderrLogger $logger) { $this->logger = $logger; } private function getAuthToken(): string { // Define connection authentication parameters $dbConnection = [ 'hostname' => getenv('DB_HOSTNAME'), 'port' => getenv('DB_PORT'), 'username' => getenv('DB_USERNAME'), 'region' => getenv('AWS_REGION'), ]; // Create RDS AuthTokenGenerator object $generator = new AuthTokenGenerator(CredentialProvider::defaultProvider()); // Request authorization token from RDS, specifying the username return $generator->createToken( $dbConnection['hostname'] . ':' . $dbConnection['port'], $dbConnection['region'], $dbConnection['username'] ); } private function getQueryResults() { // Obtain auth token $token = $this->getAuthToken(); // Define connection configuration $connectionConfig = [ 'host' => getenv('DB_HOSTNAME'), 'user' => getenv('DB_USERNAME'), 'password' => $token, 'database' => getenv('DB_NAME'), ]; // Create the connection to the DB $conn = new PDO( "mysql:host={$connectionConfig['host']};dbname={$connectionConfig['database']}", $connectionConfig['user'], $connectionConfig['password'], [ PDO::MYSQL_ATTR_SSL_CA => '/path/to/rds-ca-2019-root.pem', PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true, ] ); // Obtain the result of the query $stmt = $conn->prepare('SELECT ?+? AS sum'); $stmt->execute([3, 2]); return $stmt->fetch(PDO::FETCH_ASSOC); } /** * @param mixed $event * @param Context $context * @return array */ public function handle(mixed $event, Context $context): array { $this->logger->info("Processing query"); // Execute database flow $result = $this->getQueryResults(); return [ 'sum' => $result['sum'] ]; } } $logger = new StderrLogger(); return new Handler($logger);
Python
SDK for Python (Boto3)
注意

查看 GitHub,了解更多信息。在无服务器示例存储库中查找完整示例,并了解如何进行设置和运行。

在 Lambda 函数中使用 Python 连接到 Amazon RDS 数据库。

import json import os import boto3 import pymysql # RDS settings proxy_host_name = os.environ['PROXY_HOST_NAME'] port = int(os.environ['PORT']) db_name = os.environ['DB_NAME'] db_user_name = os.environ['DB_USER_NAME'] aws_region = os.environ['AWS_REGION'] # Fetch RDS Auth Token def get_auth_token(): client = boto3.client('rds') token = client.generate_db_auth_token( DBHostname=proxy_host_name, Port=port DBUsername=db_user_name Region=aws_region ) return token def lambda_handler(event, context): token = get_auth_token() try: connection = pymysql.connect( host=proxy_host_name, user=db_user_name, password=token, db=db_name, port=port, ssl={'ca': 'Amazon RDS'} # Ensure you have the CA bundle for SSL connection ) with connection.cursor() as cursor: cursor.execute('SELECT %s + %s AS sum', (3, 2)) result = cursor.fetchone() return result except Exception as e: return (f"Error: {str(e)}") # Return an error message if an exception occurs
Ruby
适用于 Ruby 的 SDK
注意

查看 GitHub,了解更多信息。在无服务器示例存储库中查找完整示例,并了解如何进行设置和运行。

在 Lambda 函数中使用 Ruby 连接到 Amazon RDS 数据库。

# Ruby code here. require 'aws-sdk-rds' require 'json' require 'mysql2' def lambda_handler(event:, context:) endpoint = ENV['DBEndpoint'] # Add the endpoint without https" port = ENV['Port'] # 3306 user = ENV['DBUser'] region = ENV['DBRegion'] # 'us-east-1' db_name = ENV['DBName'] credentials = Aws::Credentials.new( ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'], ENV['AWS_SESSION_TOKEN'] ) rds_client = Aws::RDS::AuthTokenGenerator.new( region: region, credentials: credentials ) token = rds_client.auth_token( endpoint: endpoint+ ':' + port, user_name: user, region: region ) begin conn = Mysql2::Client.new( host: endpoint, username: user, password: token, port: port, database: db_name, sslca: '/var/task/global-bundle.pem', sslverify: true, enable_cleartext_plugin: true ) a = 3 b = 2 result = conn.query("SELECT #{a} + #{b} AS sum").first['sum'] puts result conn.close { statusCode: 200, body: result.to_json } rescue => e puts "Database connection failed due to #{e}" end end
Rust
适用于 Rust 的 SDK
注意

查看 GitHub,了解更多信息。在无服务器示例存储库中查找完整示例,并了解如何进行设置和运行。

在 Lambda 函数中使用 Rust 连接到 Amazon RDS 数据库。

use aws_config::BehaviorVersion; use aws_credential_types::provider::ProvideCredentials; use aws_sigv4::{ http_request::{sign, SignableBody, SignableRequest, SigningSettings}, sign::v4, }; use lambda_runtime::{run, service_fn, Error, LambdaEvent}; use serde_json::{json, Value}; use sqlx::postgres::PgConnectOptions; use std::env; use std::time::{Duration, SystemTime}; const RDS_CERTS: &[u8] = include_bytes!("global-bundle.pem"); async fn generate_rds_iam_token( db_hostname: &str, port: u16, db_username: &str, ) -> Result<String, Error> { let config = aws_config::load_defaults(BehaviorVersion::v2024_03_28()).await; let credentials = config .credentials_provider() .expect("no credentials provider found") .provide_credentials() .await .expect("unable to load credentials"); let identity = credentials.into(); let region = config.region().unwrap().to_string(); let mut signing_settings = SigningSettings::default(); signing_settings.expires_in = Some(Duration::from_secs(900)); signing_settings.signature_location = aws_sigv4::http_request::SignatureLocation::QueryParams; let signing_params = v4::SigningParams::builder() .identity(&identity) .region(&region) .name("rds-db") .time(SystemTime::now()) .settings(signing_settings) .build()?; let url = format!( "https://{db_hostname}:{port}/?Action=connect&DBUser={db_user}", db_hostname = db_hostname, port = port, db_user = db_username ); let signable_request = SignableRequest::new("GET", &url, std::iter::empty(), SignableBody::Bytes(&[])) .expect("signable request"); let (signing_instructions, _signature) = sign(signable_request, &signing_params.into())?.into_parts(); let mut url = url::Url::parse(&url).unwrap(); for (name, value) in signing_instructions.params() { url.query_pairs_mut().append_pair(name, &value); } let response = url.to_string().split_off("https://".len()); Ok(response) } #[tokio::main] async fn main() -> Result<(), Error> { run(service_fn(handler)).await } async fn handler(_event: LambdaEvent<Value>) -> Result<Value, Error> { let db_host = env::var("DB_HOSTNAME").expect("DB_HOSTNAME must be set"); let db_port = env::var("DB_PORT") .expect("DB_PORT must be set") .parse::<u16>() .expect("PORT must be a valid number"); let db_name = env::var("DB_NAME").expect("DB_NAME must be set"); let db_user_name = env::var("DB_USERNAME").expect("DB_USERNAME must be set"); let token = generate_rds_iam_token(&db_host, db_port, &db_user_name).await?; let opts = PgConnectOptions::new() .host(&db_host) .port(db_port) .username(&db_user_name) .password(&token) .database(&db_name) .ssl_root_cert_from_pem(RDS_CERTS.to_vec()) .ssl_mode(sqlx::postgres::PgSslMode::Require); let pool = sqlx::postgres::PgPoolOptions::new() .connect_with(opts) .await?; let result: i32 = sqlx::query_scalar("SELECT $1 + $2") .bind(3) .bind(2) .fetch_one(&pool) .await?; println!("Result: {:?}", result); Ok(json!({ "statusCode": 200, "content-type": "text/plain", "body": format!("The selected sum is: {result}") })) }

有关 Amazon SDK 开发人员指南和代码示例的完整列表,请参阅 将此服务与 Amazon SDK 结合使用。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。