Initial commit
This commit is contained in:
400
skills/aws-java/aws-sdk-java-v2-rds/SKILL.md
Normal file
400
skills/aws-java/aws-sdk-java-v2-rds/SKILL.md
Normal file
@@ -0,0 +1,400 @@
|
||||
---
|
||||
name: aws-sdk-java-v2-rds
|
||||
description: AWS RDS (Relational Database Service) management using AWS SDK for Java 2.x. Use when creating, modifying, monitoring, or managing Amazon RDS database instances, snapshots, parameter groups, and configurations.
|
||||
category: aws
|
||||
tags: [aws, rds, database, java, sdk, postgresql, mysql, aurora, spring-boot]
|
||||
version: 1.1.0
|
||||
allowed-tools: Read, Write, Bash
|
||||
---
|
||||
|
||||
# AWS SDK for Java v2 - RDS Management
|
||||
|
||||
This skill provides comprehensive guidance for working with Amazon RDS (Relational Database Service) using the AWS SDK for Java 2.x, covering database instance management, snapshots, parameter groups, and RDS operations.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Creating and managing RDS database instances (PostgreSQL, MySQL, Aurora, etc.)
|
||||
- Taking and restoring database snapshots
|
||||
- Managing DB parameter groups and configurations
|
||||
- Querying RDS instance metadata and status
|
||||
- Setting up Multi-AZ deployments
|
||||
- Configuring automated backups
|
||||
- Managing security groups for RDS
|
||||
- Connecting Lambda functions to RDS databases
|
||||
- Implementing RDS IAM authentication
|
||||
- Monitoring RDS instances and metrics
|
||||
|
||||
## Getting Started
|
||||
|
||||
### RDS Client Setup
|
||||
|
||||
The `RdsClient` is the main entry point for interacting with Amazon RDS.
|
||||
|
||||
**Basic Client Creation:**
|
||||
```java
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.rds.RdsClient;
|
||||
|
||||
RdsClient rdsClient = RdsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
|
||||
// Use client
|
||||
describeInstances(rdsClient);
|
||||
|
||||
// Always close the client
|
||||
rdsClient.close();
|
||||
```
|
||||
|
||||
**Client with Custom Configuration:**
|
||||
```java
|
||||
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
|
||||
import software.amazon.awssdk.http.apache.ApacheHttpClient;
|
||||
|
||||
RdsClient rdsClient = RdsClient.builder()
|
||||
.region(Region.US_WEST_2)
|
||||
.credentialsProvider(ProfileCredentialsProvider.create("myprofile"))
|
||||
.httpClient(ApacheHttpClient.builder()
|
||||
.connectionTimeout(Duration.ofSeconds(30))
|
||||
.socketTimeout(Duration.ofSeconds(60))
|
||||
.build())
|
||||
.build();
|
||||
```
|
||||
|
||||
### Describing DB Instances
|
||||
|
||||
Retrieve information about existing RDS instances.
|
||||
|
||||
**List All DB Instances:**
|
||||
```java
|
||||
public static void describeInstances(RdsClient rdsClient) {
|
||||
try {
|
||||
DescribeDbInstancesResponse response = rdsClient.describeDBInstances();
|
||||
List<DBInstance> instanceList = response.dbInstances();
|
||||
|
||||
for (DBInstance instance : instanceList) {
|
||||
System.out.println("Instance ARN: " + instance.dbInstanceArn());
|
||||
System.out.println("Engine: " + instance.engine());
|
||||
System.out.println("Status: " + instance.dbInstanceStatus());
|
||||
System.out.println("Endpoint: " + instance.endpoint().address());
|
||||
System.out.println("Port: " + instance.endpoint().port());
|
||||
System.out.println("---");
|
||||
}
|
||||
} catch (RdsException e) {
|
||||
System.err.println(e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Key Operations
|
||||
|
||||
### Creating DB Instances
|
||||
|
||||
Create new RDS database instances with various configurations.
|
||||
|
||||
**Create Basic DB Instance:**
|
||||
```java
|
||||
public static String createDBInstance(RdsClient rdsClient,
|
||||
String dbInstanceIdentifier,
|
||||
String dbName,
|
||||
String masterUsername,
|
||||
String masterPassword) {
|
||||
try {
|
||||
CreateDbInstanceRequest request = CreateDbInstanceRequest.builder()
|
||||
.dbInstanceIdentifier(dbInstanceIdentifier)
|
||||
.dbName(dbName)
|
||||
.engine("postgres")
|
||||
.engineVersion("14.7")
|
||||
.dbInstanceClass("db.t3.micro")
|
||||
.allocatedStorage(20)
|
||||
.masterUsername(masterUsername)
|
||||
.masterUserPassword(masterPassword)
|
||||
.publiclyAccessible(false)
|
||||
.build();
|
||||
|
||||
CreateDbInstanceResponse response = rdsClient.createDBInstance(request);
|
||||
System.out.println("Creating DB instance: " + response.dbInstance().dbInstanceArn());
|
||||
|
||||
return response.dbInstance().dbInstanceArn();
|
||||
} catch (RdsException e) {
|
||||
System.err.println("Error creating instance: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Managing DB Parameter Groups
|
||||
|
||||
Create and manage custom parameter groups for database configuration.
|
||||
|
||||
**Create DB Parameter Group:**
|
||||
```java
|
||||
public static void createDBParameterGroup(RdsClient rdsClient,
|
||||
String groupName,
|
||||
String description) {
|
||||
try {
|
||||
CreateDbParameterGroupRequest request = CreateDbParameterGroupRequest.builder()
|
||||
.dbParameterGroupName(groupName)
|
||||
.dbParameterGroupFamily("postgres15")
|
||||
.description(description)
|
||||
.build();
|
||||
|
||||
CreateDbParameterGroupResponse response = rdsClient.createDBParameterGroup(request);
|
||||
System.out.println("Created parameter group: " + response.dbParameterGroup().dbParameterGroupName());
|
||||
} catch (RdsException e) {
|
||||
System.err.println("Error creating parameter group: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Managing DB Snapshots
|
||||
|
||||
Create, restore, and manage database snapshots.
|
||||
|
||||
**Create DB Snapshot:**
|
||||
```java
|
||||
public static String createDBSnapshot(RdsClient rdsClient,
|
||||
String dbInstanceIdentifier,
|
||||
String snapshotIdentifier) {
|
||||
try {
|
||||
CreateDbSnapshotRequest request = CreateDbSnapshotRequest.builder()
|
||||
.dbInstanceIdentifier(dbInstanceIdentifier)
|
||||
.dbSnapshotIdentifier(snapshotIdentifier)
|
||||
.build();
|
||||
|
||||
CreateDbSnapshotResponse response = rdsClient.createDBSnapshot(request);
|
||||
System.out.println("Creating snapshot: " + response.dbSnapshot().dbSnapshotIdentifier());
|
||||
|
||||
return response.dbSnapshot().dbSnapshotArn();
|
||||
} catch (RdsException e) {
|
||||
System.err.println("Error creating snapshot: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### Spring Boot Integration
|
||||
|
||||
Refer to [references/spring-boot-integration.md](references/spring-boot-integration.md) for complete Spring Boot integration examples including:
|
||||
|
||||
- Spring Boot configuration with application properties
|
||||
- RDS client bean configuration
|
||||
- Service layer implementation
|
||||
- REST controller design
|
||||
- Exception handling
|
||||
- Testing strategies
|
||||
|
||||
### Lambda Integration
|
||||
|
||||
Refer to [references/lambda-integration.md](references/lambda-integration.md) for Lambda integration examples including:
|
||||
|
||||
- Traditional Lambda + RDS connections
|
||||
- Lambda with connection pooling
|
||||
- Using AWS Secrets Manager for credentials
|
||||
- Lambda with AWS SDK for RDS management
|
||||
- Security configuration and best practices
|
||||
|
||||
## Advanced Operations
|
||||
|
||||
### Modifying DB Instances
|
||||
|
||||
Update existing RDS instances.
|
||||
|
||||
```java
|
||||
public static void modifyDBInstance(RdsClient rdsClient,
|
||||
String dbInstanceIdentifier,
|
||||
String newInstanceClass) {
|
||||
try {
|
||||
ModifyDbInstanceRequest request = ModifyDbInstanceRequest.builder()
|
||||
.dbInstanceIdentifier(dbInstanceIdentifier)
|
||||
.dbInstanceClass(newInstanceClass)
|
||||
.applyImmediately(false) // Apply during maintenance window
|
||||
.build();
|
||||
|
||||
ModifyDbInstanceResponse response = rdsClient.modifyDBInstance(request);
|
||||
System.out.println("Modified instance: " + response.dbInstance().dbInstanceIdentifier());
|
||||
System.out.println("New class: " + response.dbInstance().dbInstanceClass());
|
||||
} catch (RdsException e) {
|
||||
System.err.println("Error modifying instance: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deleting DB Instances
|
||||
|
||||
Delete RDS instances with optional final snapshot.
|
||||
|
||||
```java
|
||||
public static void deleteDBInstanceWithSnapshot(RdsClient rdsClient,
|
||||
String dbInstanceIdentifier,
|
||||
String finalSnapshotIdentifier) {
|
||||
try {
|
||||
DeleteDbInstanceRequest request = DeleteDbInstanceRequest.builder()
|
||||
.dbInstanceIdentifier(dbInstanceIdentifier)
|
||||
.skipFinalSnapshot(false)
|
||||
.finalDBSnapshotIdentifier(finalSnapshotIdentifier)
|
||||
.build();
|
||||
|
||||
DeleteDbInstanceResponse response = rdsClient.deleteDBInstance(request);
|
||||
System.out.println("Deleting instance: " + response.dbInstance().dbInstanceIdentifier());
|
||||
} catch (RdsException e) {
|
||||
System.err.println("Error deleting instance: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Security
|
||||
|
||||
**Always use encryption:**
|
||||
```java
|
||||
CreateDbInstanceRequest request = CreateDbInstanceRequest.builder()
|
||||
.storageEncrypted(true)
|
||||
.kmsKeyId("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012")
|
||||
.build();
|
||||
```
|
||||
|
||||
**Use VPC security groups:**
|
||||
```java
|
||||
CreateDbInstanceRequest request = CreateDbInstanceRequest.builder()
|
||||
.vpcSecurityGroupIds("sg-12345678")
|
||||
.publiclyAccessible(false)
|
||||
.build();
|
||||
```
|
||||
|
||||
### High Availability
|
||||
|
||||
**Enable Multi-AZ for production:**
|
||||
```java
|
||||
CreateDbInstanceRequest request = CreateDbInstanceRequest.builder()
|
||||
.multiAZ(true)
|
||||
.build();
|
||||
```
|
||||
|
||||
### Backups
|
||||
|
||||
**Configure automated backups:**
|
||||
```java
|
||||
CreateDbInstanceRequest request = CreateDbInstanceRequest.builder()
|
||||
.backupRetentionPeriod(7)
|
||||
.preferredBackupWindow("03:00-04:00")
|
||||
.build();
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
|
||||
**Enable CloudWatch logs:**
|
||||
```java
|
||||
CreateDbInstanceRequest request = CreateDbInstanceRequest.builder()
|
||||
.enableCloudwatchLogsExports("postgresql", "upgrade")
|
||||
.build();
|
||||
```
|
||||
|
||||
### Cost Optimization
|
||||
|
||||
**Use appropriate instance class:**
|
||||
```java
|
||||
// Development
|
||||
.dbInstanceClass("db.t3.micro")
|
||||
|
||||
// Production
|
||||
.dbInstanceClass("db.r5.large")
|
||||
```
|
||||
|
||||
### Deletion Protection
|
||||
|
||||
**Enable for production databases:**
|
||||
```java
|
||||
CreateDbInstanceRequest request = CreateDbInstanceRequest.builder()
|
||||
.deletionProtection(true)
|
||||
.build();
|
||||
```
|
||||
|
||||
### Resource Management
|
||||
|
||||
**Always close clients:**
|
||||
```java
|
||||
try (RdsClient rdsClient = RdsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build()) {
|
||||
// Use client
|
||||
} // Automatically closed
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Maven Dependencies
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<!-- AWS SDK for RDS -->
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>rds</artifactId>
|
||||
<version>2.20.0</version> // Use the latest version available
|
||||
</dependency>
|
||||
|
||||
<!-- PostgreSQL Driver -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.6.0</version> // Use the correct version available
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL Driver -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
### Gradle Dependencies
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
// AWS SDK for RDS
|
||||
implementation 'software.amazon.awssdk:rds:2.20.0'
|
||||
|
||||
// PostgreSQL Driver
|
||||
implementation 'org.postgresql:postgresql:42.6.0'
|
||||
|
||||
// MySQL Driver
|
||||
implementation 'mysql:mysql-connector-java:8.0.33'
|
||||
}
|
||||
```
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
For detailed API reference, see:
|
||||
- [API Reference](references/api-reference.md) - Complete API documentation and data models
|
||||
- [Spring Boot Integration](references/spring-boot-integration.md) - Spring Boot patterns and examples
|
||||
- [Lambda Integration](references/lambda-integration.md) - Lambda function patterns and best practices
|
||||
|
||||
## Error Handling
|
||||
|
||||
See [API Reference](references/api-reference.md#error-handling) for comprehensive error handling patterns including common exceptions, error response structure, and pagination support.
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- Use connection pooling for multiple database operations
|
||||
- Implement retry logic for transient failures
|
||||
- Monitor CloudWatch metrics for performance optimization
|
||||
- Use appropriate instance types for workload requirements
|
||||
- Enable Performance Insights for database optimization
|
||||
|
||||
## Support
|
||||
|
||||
For support with AWS RDS operations using AWS SDK for Java 2.x:
|
||||
- AWS Documentation: [Amazon RDS User Guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html)
|
||||
- AWS SDK Documentation: [AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html)
|
||||
- AWS Support: [AWS Support Center](https://aws.amazon.com/premiumsupport/)
|
||||
122
skills/aws-java/aws-sdk-java-v2-rds/references/api-reference.md
Normal file
122
skills/aws-java/aws-sdk-java-v2-rds/references/api-reference.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# AWS RDS API Reference
|
||||
|
||||
## Core API Operations
|
||||
|
||||
### Describe Operations
|
||||
- `describeDBInstances` - List database instances
|
||||
- `describeDBParameterGroups` - List parameter groups
|
||||
- `describeDBSnapshots` - List database snapshots
|
||||
- `describeDBSubnetGroups` - List subnet groups
|
||||
|
||||
### Instance Management
|
||||
- `createDBInstance` - Create new database instance
|
||||
- `modifyDBInstance` - Modify existing instance
|
||||
- `deleteDBInstance` - Delete database instance
|
||||
|
||||
### Parameter Groups
|
||||
- `createDBParameterGroup` - Create parameter group
|
||||
- `modifyDBParameterGroup` - Modify parameters
|
||||
- `deleteDBParameterGroup` - Delete parameter group
|
||||
|
||||
### Snapshots
|
||||
- `createDBSnapshot` - Create database snapshot
|
||||
- `restoreDBInstanceFromDBSnapshot` - Restore from snapshot
|
||||
- `deleteDBSnapshot` - Delete snapshot
|
||||
|
||||
## Key Data Models
|
||||
|
||||
### DBInstance
|
||||
```java
|
||||
String dbInstanceIdentifier() // Instance name
|
||||
String dbInstanceArn() // ARN identifier
|
||||
String engine() // Database engine
|
||||
String engineVersion() // Engine version
|
||||
String dbInstanceClass() // Instance type
|
||||
int allocatedStorage() // Storage size in GB
|
||||
Endpoint endpoint() // Connection endpoint
|
||||
String dbInstanceStatus() // Instance status
|
||||
boolean multiAZ() // Multi-AZ enabled
|
||||
boolean storageEncrypted() // Storage encrypted
|
||||
```
|
||||
|
||||
### DBParameter
|
||||
```java
|
||||
String parameterName() // Parameter name
|
||||
String parameterValue() // Parameter value
|
||||
String description() // Description
|
||||
int applyMethod() // Apply method (immediate/reboot)
|
||||
```
|
||||
|
||||
### CreateDbInstanceRequest Builder
|
||||
```java
|
||||
CreateDbInstanceRequest.builder()
|
||||
.dbInstanceIdentifier(identifier)
|
||||
.engine("postgres") // Database engine
|
||||
.engineVersion("15.2") // Engine version
|
||||
.dbInstanceClass("db.t3.micro") // Instance type
|
||||
.allocatedStorage(20) // Storage size
|
||||
.masterUsername(username) // Admin username
|
||||
.masterUserPassword(password) // Admin password
|
||||
.publiclyAccessible(false) // Public access
|
||||
.storageEncrypted(true) // Storage encryption
|
||||
.multiAZ(true) // High availability
|
||||
.backupRetentionPeriod(7) // Backup retention
|
||||
.deletionProtection(true) // Protection from deletion
|
||||
.build()
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Exceptions
|
||||
- `DBInstanceNotFoundFault` - Instance doesn't exist
|
||||
- `DBSnapshotAlreadyExistsFault` - Snapshot name conflicts
|
||||
- `InsufficientDBInstanceCapacity` - Instance type unavailable
|
||||
- `InvalidParameterValueException` - Invalid configuration value
|
||||
- `StorageQuotaExceeded` - Storage limit reached
|
||||
|
||||
### Error Response Structure
|
||||
```java
|
||||
try {
|
||||
rdsClient.createDBInstance(request);
|
||||
} catch (RdsException e) {
|
||||
// AWS specific error handling
|
||||
String errorCode = e.awsErrorDetails().errorCode();
|
||||
String errorMessage = e.awsErrorDetails().errorMessage();
|
||||
|
||||
switch (errorCode) {
|
||||
case "DBInstanceNotFoundFault":
|
||||
// Handle missing instance
|
||||
break;
|
||||
case "InvalidParameterValueException":
|
||||
// Handle invalid parameters
|
||||
break;
|
||||
default:
|
||||
// Generic error handling
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Pagination Support
|
||||
|
||||
### List Instances with Pagination
|
||||
```java
|
||||
DescribeDbInstancesRequest request = DescribeDbInstancesRequest.builder()
|
||||
.maxResults(100) // Limit results per page
|
||||
.build();
|
||||
|
||||
String marker = null;
|
||||
do {
|
||||
if (marker != null) {
|
||||
request = request.toBuilder()
|
||||
.marker(marker)
|
||||
.build();
|
||||
}
|
||||
|
||||
DescribeDbInstancesResponse response = rdsClient.describeDBInstances(request);
|
||||
List<DBInstance> instances = response.dbInstances();
|
||||
|
||||
// Process instances
|
||||
|
||||
marker = response.marker();
|
||||
} while (marker != null);
|
||||
```
|
||||
@@ -0,0 +1,382 @@
|
||||
# AWS Lambda Integration with RDS
|
||||
|
||||
## Lambda RDS Connection Patterns
|
||||
|
||||
### 1. Traditional Lambda + RDS Connection
|
||||
|
||||
```java
|
||||
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 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 {
|
||||
// Get environment variables
|
||||
String host = System.getenv("ProxyHostName");
|
||||
String port = System.getenv("Port");
|
||||
String dbName = System.getenv("DBName");
|
||||
String username = System.getenv("DBUserName");
|
||||
String password = System.getenv("DBPassword");
|
||||
|
||||
// Create connection string
|
||||
String connectionString = String.format(
|
||||
"jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true",
|
||||
host, port, dbName
|
||||
);
|
||||
|
||||
// Execute query
|
||||
String sql = "SELECT COUNT(*) FROM users";
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(connectionString, username, password);
|
||||
PreparedStatement statement = connection.prepareStatement(sql);
|
||||
ResultSet resultSet = statement.executeQuery()) {
|
||||
|
||||
if (resultSet.next()) {
|
||||
int count = resultSet.getInt(1);
|
||||
response.setStatusCode(200);
|
||||
response.setBody("{\"count\": " + count + "}");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
response.setStatusCode(500);
|
||||
response.setBody("{\"error\": \"" + e.getMessage() + "\"}");
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Lambda with Connection Pooling
|
||||
|
||||
```java
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
public class RdsLambdaConfig {
|
||||
|
||||
private static DataSource dataSource;
|
||||
|
||||
public static synchronized DataSource getDataSource() {
|
||||
if (dataSource == null) {
|
||||
HikariConfig config = new HikariConfig();
|
||||
|
||||
String host = System.getenv("ProxyHostName");
|
||||
String port = System.getenv("Port");
|
||||
String dbName = System.getenv("DBName");
|
||||
String username = System.getenv("DBUserName");
|
||||
String password = System.getenv("DBPassword");
|
||||
|
||||
config.setJdbcUrl(String.format("jdbc:mysql://%s:%s/%s", host, port, dbName));
|
||||
config.setUsername(username);
|
||||
config.setPassword(password);
|
||||
|
||||
// Connection pool settings
|
||||
config.setMaximumPoolSize(5);
|
||||
config.setMinimumIdle(2);
|
||||
config.setIdleTimeout(30000);
|
||||
config.setConnectionTimeout(20000);
|
||||
config.setMaxLifetime(1800000);
|
||||
|
||||
// MySQL-specific settings
|
||||
config.addDataSourceProperty("useSSL", true);
|
||||
config.addDataSourceProperty("requireSSL", true);
|
||||
config.addDataSourceProperty("serverSslCertificate", "rds-ca-2019");
|
||||
config.addDataSourceProperty("connectTimeout", "30");
|
||||
|
||||
dataSource = new HikariDataSource(config);
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Using AWS Secrets Manager for Credentials
|
||||
|
||||
```java
|
||||
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
|
||||
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
|
||||
import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest;
|
||||
import com.amazonaws.services.secretsmanager.model.GetSecretValueResult;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RdsSecretsHelper {
|
||||
|
||||
private static final String SECRET_NAME = "prod/rds/db_credentials";
|
||||
private static final String REGION = "us-east-1";
|
||||
|
||||
public static Map<String, String> getRdsCredentials() {
|
||||
AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard()
|
||||
.withRegion(REGION)
|
||||
.build();
|
||||
|
||||
GetSecretValueRequest request = GetSecretValueRequest.builder()
|
||||
.secretId(SECRET_NAME)
|
||||
.build();
|
||||
|
||||
GetSecretValueResult result = client.getSecretValue(request);
|
||||
|
||||
// Parse secret JSON
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
Map<String, Object> secretMap = objectMapper.readValue(result.getSecretString(), HashMap.class);
|
||||
|
||||
Map<String, String> credentials = new HashMap<>();
|
||||
secretMap.forEach((key, value) -> {
|
||||
credentials.put(key, value.toString());
|
||||
});
|
||||
|
||||
return credentials;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Lambda with AWS SDK for RDS
|
||||
|
||||
```java
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.rds.RdsClient;
|
||||
import software.amazon.awssdk.services.rds.model.*;
|
||||
|
||||
public class RdsManagementLambda implements RequestHandler<ApiRequest, ApiResponse> {
|
||||
|
||||
@Override
|
||||
public ApiResponse handleRequest(ApiRequest request, Context context) {
|
||||
RdsClient rdsClient = RdsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
|
||||
try {
|
||||
switch (request.getAction()) {
|
||||
case "list-instances":
|
||||
return listInstances(rdsClient);
|
||||
case "create-snapshot":
|
||||
return createSnapshot(rdsClient, request.getInstanceId(), request.getSnapshotId());
|
||||
case "describe-instance":
|
||||
return describeInstance(rdsClient, request.getInstanceId());
|
||||
default:
|
||||
return new ApiResponse(400, "Unknown action: " + request.getAction());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
context.getLogger().log("Error: " + e.getMessage());
|
||||
return new ApiResponse(500, "Error: " + e.getMessage());
|
||||
} finally {
|
||||
rdsClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
private ApiResponse listInstances(RdsClient rdsClient) {
|
||||
DescribeDbInstancesResponse response = rdsClient.describeDBInstances();
|
||||
return new ApiResponse(200, response.toString());
|
||||
}
|
||||
|
||||
private ApiResponse createSnapshot(RdsClient rdsClient, String instanceId, String snapshotId) {
|
||||
CreateDbSnapshotRequest request = CreateDbSnapshotRequest.builder()
|
||||
.dbInstanceIdentifier(instanceId)
|
||||
.dbSnapshotIdentifier(snapshotId)
|
||||
.build();
|
||||
|
||||
CreateDbSnapshotResponse response = rdsClient.createDBSnapshot(request);
|
||||
return new ApiResponse(200, "Snapshot created: " + response.dbSnapshot().dbSnapshotIdentifier());
|
||||
}
|
||||
|
||||
private ApiResponse describeInstance(RdsClient rdsClient, String instanceId) {
|
||||
DescribeDbInstancesRequest request = DescribeDbInstancesRequest.builder()
|
||||
.dbInstanceIdentifier(instanceId)
|
||||
.build();
|
||||
|
||||
DescribeDbInstancesResponse response = rdsClient.describeDBInstances(request);
|
||||
return new ApiResponse(200, response.toString());
|
||||
}
|
||||
}
|
||||
|
||||
class ApiRequest {
|
||||
private String action;
|
||||
private String instanceId;
|
||||
private String snapshotId;
|
||||
// getters and setters
|
||||
}
|
||||
|
||||
class ApiResponse {
|
||||
private int statusCode;
|
||||
private String body;
|
||||
// constructor, getters
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices for Lambda + RDS
|
||||
|
||||
### 1. Security Configuration
|
||||
|
||||
**IAM Role:**
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"rds:*"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Security Group:**
|
||||
- Use security groups to restrict access
|
||||
- Only allow Lambda function IP ranges
|
||||
- Use VPC endpoints for private connections
|
||||
|
||||
### 2. Environment Variables
|
||||
|
||||
```bash
|
||||
# Environment variables for Lambda
|
||||
DB_HOST=mydb.abc123.us-east-1.rds.amazonaws.com
|
||||
DB_PORT=5432
|
||||
DB_NAME=mydatabase
|
||||
DB_USERNAME=admin
|
||||
DB_PASSWORD=${DB_PASSWORD}
|
||||
DB_CONNECTION_STRING=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||
```
|
||||
|
||||
### 3. Error Handling
|
||||
|
||||
```java
|
||||
import com.amazonaws.services.lambda.runtime.LambdaLogger;
|
||||
|
||||
public class LambdaErrorHandler {
|
||||
|
||||
public static void handleRdsError(Exception e, LambdaLogger logger) {
|
||||
if (e instanceof RdsException) {
|
||||
RdsException rdsException = (RdsException) e;
|
||||
logger.log("RDS Error: " + rdsException.awsErrorDetails().errorCode());
|
||||
|
||||
switch (rdsException.awsErrorDetails().errorCode()) {
|
||||
case "DBInstanceNotFoundFault":
|
||||
logger.log("Database instance not found");
|
||||
break;
|
||||
case "InvalidParameterValueException":
|
||||
logger.log("Invalid parameter provided");
|
||||
break;
|
||||
case "InstanceAlreadyExistsFault":
|
||||
logger.log("Instance already exists");
|
||||
break;
|
||||
default:
|
||||
logger.log("Unknown RDS error: " + rdsException.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.log("Non-RDS error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Performance Optimization
|
||||
|
||||
**Cold Start Mitigation:**
|
||||
```java
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
|
||||
public class RdsConnectionHelper {
|
||||
private static DataSource dataSource;
|
||||
private static long lastConnectionTime = 0;
|
||||
private static final long CONNECTION_TIMEOUT = 300000; // 5 minutes
|
||||
|
||||
public static Connection getConnection() throws SQLException {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
if (dataSource == null || (currentTime - lastConnectionTime) > CONNECTION_TIMEOUT) {
|
||||
dataSource = createDataSource();
|
||||
lastConnectionTime = currentTime;
|
||||
}
|
||||
|
||||
return dataSource.getConnection();
|
||||
}
|
||||
|
||||
private static DataSource createDataSource() {
|
||||
// Connection pool creation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Batch Processing:**
|
||||
```java
|
||||
public class RdsBatchProcessor {
|
||||
|
||||
public void processBatch(List<String> userIds) {
|
||||
String sql = "SELECT * FROM users WHERE user_id IN (?)";
|
||||
|
||||
try (Connection connection = getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||
|
||||
// Convert list to SQL IN clause
|
||||
String placeholders = userIds.stream()
|
||||
.map(id -> "?")
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
String finalSql = sql.replace("?", placeholders);
|
||||
|
||||
// Set parameters
|
||||
for (int i = 0; i < userIds.size(); i++) {
|
||||
statement.setString(i + 1, userIds.get(i));
|
||||
}
|
||||
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
// Process results
|
||||
|
||||
} catch (SQLException e) {
|
||||
LambdaErrorHandler.handleRdsError(e, logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Monitoring and Logging
|
||||
|
||||
```java
|
||||
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
|
||||
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
|
||||
import com.amazonaws.services.cloudwatch.model.MetricDatum;
|
||||
import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest;
|
||||
|
||||
public class RdsMetricsPublisher {
|
||||
|
||||
private static final String NAMESPACE = "RDS/Lambda";
|
||||
private AmazonCloudWatch cloudWatch;
|
||||
|
||||
public RdsMetricsPublisher() {
|
||||
this.cloudWatch = AmazonCloudWatchClientBuilder.defaultClient();
|
||||
}
|
||||
|
||||
public void publishMetric(String metricName, double value) {
|
||||
MetricDatum datum = new MetricDatum()
|
||||
.withMetricName(metricName)
|
||||
.withUnit("Count")
|
||||
.withValue(value)
|
||||
.withTimestamp(new Date());
|
||||
|
||||
PutMetricDataRequest request = new PutMetricDataRequest()
|
||||
.withNamespace(NAMESPACE)
|
||||
.withMetricData(Collections.singletonList(datum));
|
||||
|
||||
cloudWatch.putMetricData(request);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,325 @@
|
||||
# Spring Boot Integration with AWS RDS
|
||||
|
||||
## Configuration
|
||||
|
||||
### application.properties
|
||||
```properties
|
||||
# AWS Configuration
|
||||
aws.region=us-east-1
|
||||
aws.rds.instance-identifier=mydb-instance
|
||||
|
||||
# RDS Connection (from RDS endpoint)
|
||||
spring.datasource.url=jdbc:postgresql://mydb.abc123.us-east-1.rds.amazonaws.com:5432/mydatabase
|
||||
spring.datasource.username=admin
|
||||
spring.datasource.password=${DB_PASSWORD}
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
|
||||
# JPA Configuration
|
||||
spring.jpa.hibernate.ddl-auto=validate
|
||||
spring.jpa.show-sql=false
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
|
||||
|
||||
# Connection Pool Configuration
|
||||
spring.datasource.hikari.maximum-pool-size=10
|
||||
spring.datasource.hikari.minimum-idle=5
|
||||
spring.datasource.hikari.idle-timeout=30000
|
||||
spring.datasource.hikari.connection-timeout=20000
|
||||
```
|
||||
|
||||
### AWS Configuration
|
||||
```java
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.rds.RdsClient;
|
||||
|
||||
@Configuration
|
||||
public class AwsRdsConfig {
|
||||
|
||||
@Value("${aws.region}")
|
||||
private String awsRegion;
|
||||
|
||||
@Bean
|
||||
public RdsClient rdsClient() {
|
||||
return RdsClient.builder()
|
||||
.region(Region.of(awsRegion))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Service Layer
|
||||
```java
|
||||
import org.springframework.stereotype.Service;
|
||||
import software.amazon.awssdk.services.rds.RdsClient;
|
||||
import software.amazon.awssdk.services.rds.model.*;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class RdsService {
|
||||
|
||||
private final RdsClient rdsClient;
|
||||
|
||||
public RdsService(RdsClient rdsClient) {
|
||||
this.rdsClient = rdsClient;
|
||||
}
|
||||
|
||||
public List<DBInstance> listInstances() {
|
||||
DescribeDbInstancesResponse response = rdsClient.describeDBInstances();
|
||||
return response.dbInstances();
|
||||
}
|
||||
|
||||
public DBInstance getInstanceDetails(String instanceId) {
|
||||
DescribeDbInstancesRequest request = DescribeDbInstancesRequest.builder()
|
||||
.dbInstanceIdentifier(instanceId)
|
||||
.build();
|
||||
|
||||
DescribeDbInstancesResponse response = rdsClient.describeDBInstances(request);
|
||||
return response.dbInstances().get(0);
|
||||
}
|
||||
|
||||
public String createSnapshot(String instanceId, String snapshotId) {
|
||||
CreateDbSnapshotRequest request = CreateDbSnapshotRequest.builder()
|
||||
.dbInstanceIdentifier(instanceId)
|
||||
.dbSnapshotIdentifier(snapshotId)
|
||||
.build();
|
||||
|
||||
CreateDbSnapshotResponse response = rdsClient.createDBSnapshot(request);
|
||||
return response.dbSnapshot().dbSnapshotArn();
|
||||
}
|
||||
|
||||
public void modifyInstance(String instanceId, String newInstanceClass) {
|
||||
ModifyDbInstanceRequest request = ModifyDbInstanceRequest.builder()
|
||||
.dbInstanceIdentifier(instanceId)
|
||||
.dbInstanceClass(newInstanceClass)
|
||||
.applyImmediately(true)
|
||||
.build();
|
||||
|
||||
rdsClient.modifyDBInstance(request);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### REST Controller
|
||||
```java
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import software.amazon.awssdk.services.rds.model.DBInstance;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/rds")
|
||||
public class RdsController {
|
||||
|
||||
private final RdsService rdsService;
|
||||
|
||||
public RdsController(RdsService rdsService) {
|
||||
this.rdsService = rdsService;
|
||||
}
|
||||
|
||||
@GetMapping("/instances")
|
||||
public ResponseEntity<List<DBInstance>> listInstances() {
|
||||
return ResponseEntity.ok(rdsService.listInstances());
|
||||
}
|
||||
|
||||
@GetMapping("/instances/{id}")
|
||||
public ResponseEntity<DBInstance> getInstanceDetails(@PathVariable String id) {
|
||||
return ResponseEntity.ok(rdsService.getInstanceDetails(id));
|
||||
}
|
||||
|
||||
@PostMapping("/snapshots")
|
||||
public ResponseEntity<String> createSnapshot(
|
||||
@RequestParam String instanceId,
|
||||
@RequestParam String snapshotId) {
|
||||
String arn = rdsService.createSnapshot(instanceId, snapshotId);
|
||||
return ResponseEntity.ok(arn);
|
||||
}
|
||||
|
||||
@PutMapping("/instances/{id}")
|
||||
public ResponseEntity<String> modifyInstance(
|
||||
@PathVariable String id,
|
||||
@RequestParam String instanceClass) {
|
||||
rdsService.modifyInstance(id, instanceClass);
|
||||
return ResponseEntity.ok("Instance modified successfully");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Exception Handling
|
||||
```java
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class RdsExceptionHandler {
|
||||
|
||||
@ExceptionHandler(RdsException.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public ErrorResponse handleRdsException(RdsException e) {
|
||||
return new ErrorResponse(
|
||||
"RDS_ERROR",
|
||||
e.getMessage(),
|
||||
e.awsErrorDetails().errorCode()
|
||||
);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public ErrorResponse handleGenericException(Exception e) {
|
||||
return new ErrorResponse(
|
||||
"INTERNAL_ERROR",
|
||||
e.getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorResponse {
|
||||
private String code;
|
||||
private String message;
|
||||
private String details;
|
||||
|
||||
// Constructor, getters, setters
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
```java
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RdsServiceTest {
|
||||
|
||||
@Mock
|
||||
private RdsClient rdsClient;
|
||||
|
||||
@Test
|
||||
void listInstances_shouldReturnInstances() {
|
||||
// Arrange
|
||||
DescribeDbInstancesResponse response = DescribeDbInstancesResponse.builder()
|
||||
.dbInstances(List.of(createTestInstance()))
|
||||
.build();
|
||||
|
||||
when(rdsClient.describeDBInstances()).thenReturn(response);
|
||||
|
||||
RdsService service = new RdsService(rdsClient);
|
||||
|
||||
// Act
|
||||
List<DBInstance> result = service.listInstances();
|
||||
|
||||
// Assert
|
||||
assertEquals(1, result.size());
|
||||
verify(rdsClient).describeDBInstances();
|
||||
}
|
||||
|
||||
private DBInstance createTestInstance() {
|
||||
return DBInstance.builder()
|
||||
.dbInstanceIdentifier("test-instance")
|
||||
.engine("postgres")
|
||||
.dbInstanceStatus("available")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
```java
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@SpringBootTest
|
||||
@ActiveProfiles = "test"
|
||||
class RdsServiceIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private RdsService rdsService;
|
||||
|
||||
@Test
|
||||
void listInstances_integrationTest() {
|
||||
// This test requires actual AWS credentials and RDS instances
|
||||
// Should only run with proper test configuration
|
||||
assumeTrue(false, "Integration test disabled");
|
||||
|
||||
List<DBInstance> instances = rdsService.listInstances();
|
||||
assertNotNull(instances);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Configuration Management
|
||||
- Use Spring profiles for different environments
|
||||
- Externalize sensitive configuration (passwords, keys)
|
||||
- Use Spring Cloud Config for multi-environment management
|
||||
|
||||
### 2. Connection Pooling
|
||||
```properties
|
||||
# HikariCP Configuration
|
||||
spring.datasource.hikari.maximum-pool-size=20
|
||||
spring.datasource.hikari.minimum-idle=10
|
||||
spring.datasource.hikari.idle-timeout=600000
|
||||
spring.datasource.hikari.connection-timeout=30000
|
||||
spring.datasource.hikari.connection-test-query=SELECT 1
|
||||
```
|
||||
|
||||
### 3. Retry Logic
|
||||
```java
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
|
||||
@Service
|
||||
public class RdsServiceWithRetry {
|
||||
|
||||
private final RdsClient rdsClient;
|
||||
|
||||
@Retryable(value = { RdsException.class },
|
||||
maxAttempts = 3,
|
||||
backoff = @Backoff(delay = 1000))
|
||||
public List<DBInstance> listInstancesWithRetry() {
|
||||
return rdsClient.describeDBInstances().dbInstances();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Monitoring
|
||||
```java
|
||||
import org.springframework.boot.actuator.health.Health;
|
||||
import org.springframework.boot.actuator.health.HealthIndicator;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class RdsHealthIndicator implements HealthIndicator {
|
||||
|
||||
private final RdsClient rdsClient;
|
||||
|
||||
public RdsHealthIndicator(RdsClient rdsClient) {
|
||||
this.rdsClient = rdsClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Health health() {
|
||||
try {
|
||||
rdsClient.describeDBInstances();
|
||||
return Health.up()
|
||||
.withDetail("service", "RDS")
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
return Health.down()
|
||||
.withDetail("error", e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user