快速入门:将 Java和 JDBC 与 Azure Database for PostgreSQL 灵活服务器配合使用

适用于: Azure Database for PostgreSQL 灵活服务器

本文演示如何创建示例应用程序,使其使用 Java 和 JDBCAzure Database for PostgreSQL 灵活服务器中存储和检索信息。

JDBC 是标准的 Java API,用于连接到传统的关系数据库。

在本文中,我们将讨论两种身份验证方法:Microsoft Entra 身份验证和 PostgreSQL 身份验证。 “无密码”选项卡可显示 Microsoft Entra 身份验证,“密码”选项卡则显示 PostgreSQL 身份验证

Microsoft Entra 身份验证是一种使用 Microsoft Entra ID 中定义的标识连接到 Azure Database for PostgreSQL 的机制。 通过 Microsoft Entra 身份验证,可以在一个中心位置集中管理数据库用户标识和其他 Microsoft 服务,从而简化权限管理。

PostgreSQL 身份验证使用存储在 PostgreSQL 中的帐户。 如果你选择使用密码作为帐户的凭据,这些凭据将存储在 user 表中。 由于这些密码存储在 PostgreSQL 中,因此你需要自行管理密码的轮换。

先决条件

准备工作环境

首先,使用以下命令设置一些环境变量。

export AZ_RESOURCE_GROUP=database-workshop
export AZ_DATABASE_SERVER_NAME=<YOUR_DATABASE_SERVER_NAME>
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_POSTGRESQL_AD_NON_ADMIN_USERNAME=<YOUR_POSTGRESQL_AD_NON_ADMIN_USERNAME>
export AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>
export CURRENT_USERNAME=$(az ad signed-in-user show --query userPrincipalName -o tsv)

使用以下值替换占位符,在本文中将使用这些值:

  • <YOUR_DATABASE_SERVER_NAME>:Azure Database for PostgreSQL 灵活服务器实例的名称,在 Azure 中应是唯一的。
  • <YOUR_DATABASE_NAME>:Azure Database for PostgreSQL 灵活服务器实例的数据库名称,在 Azure 中应是唯一的。
  • <YOUR_AZURE_REGION>:要使用的 Azure 区域。 默认情况下可以使用 chinanorth3,但我们建议你配置一个离居住位置更近的区域。 可以通过输入 az account list-locations 查看可用区域的完整列表。
  • <YOUR_POSTGRESQL_AD_NON_ADMIN_USERNAME>:Azure Database for PostgreSQL 灵活服务器实例的用户名。 确保用户名是 Microsoft Entra 租户中的有效用户。
  • <YOUR_LOCAL_IP_ADDRESS>:你将在其中运行 Spring Boot 应用程序的本地计算机的 IP 地址。 一种查看 IP 地址的便捷方法是打开 whatismyip.akamai.com

重要

在设置 <YOUR_POSTGRESQL_AD_NON_ADMIN_USERNAME> 时,用户名必须已存在于 Microsoft Entra 租户中,否则将无法在数据库中创建 Microsoft Entra 用户。

接下来,请使用以下命令创建资源组:

az group create \
    --name $AZ_RESOURCE_GROUP \
    --location $AZ_LOCATION \
    --output tsv

创建 Azure Database for PostgreSQL 灵活服务器实例

以下部分介绍了如何创建和配置数据库实例。

创建 Azure Database for PostgreSQL 灵活服务器实例并设置管理员用户

首先需要创建托管的 Azure Database for PostgreSQL 灵活服务器实例。

注意

可在“使用 Azure 门户创建 Azure Database for PostgreSQL 灵活服务器实例”中阅读有关创建 Azure Database for PostgreSQL 灵活服务器实例的更多详细信息。

如果使用 Azure CLI,请运行以下命令以确保该用户拥有足够的权限:

az login --scope https://microsoftgraph.chinacloudapi.cn/.default

运行以下命令以创建服务器:

az postgres flexible-server create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME \
    --location $AZ_LOCATION \
    --yes \
    --output tsv

若要在创建服务器后设置 Microsoft Entra 管理员,请按照在 Azure Database for PostgreSQL - 灵活服务器中管理 Microsoft Entra 角色中的步骤操作。

重要

设置管理员时,将具有完全管理员特权的新用户添加到 Azure Database for PostgreSQL 灵活服务器实例的 Azure 数据库。 可为每个 Azure Database for PostgreSQL 灵活服务器实例创建多个 Microsoft Entra 管理员。

为 Azure Database for PostgreSQL 灵活服务器实例配置防火墙规则

Azure Database for PostgreSQL 灵活服务器实例在默认情况下受保护。 它们有不允许任何传入连接的防火墙。 为了能够使用数据库,需要添加一项防火墙规则,允许本地 IP 地址访问数据库服务器。

由于我们已在本文开头配置了本地 IP 地址,因此你可通过运行以下命令来打开服务器的防火墙:

az postgres flexible-server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME \
    --rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
    --start-ip-address $AZ_LOCAL_IP_ADDRESS \
    --end-ip-address $AZ_LOCAL_IP_ADDRESS \
    --output tsv

如果要在 Windows 计算机上从适用于 Linux 的 Windows 子系统 (WSL) 连接到 Azure Database for PostgreSQL 灵活服务器实例,需要将 WSL 主机 ID 添加到防火墙。

通过在 WSL 中运行以下命令获取主机的 IP 地址:

cat /etc/resolv.conf

复制 nameserver 一词后面的 IP 地址,然后使用以下命令为 WSL IP 地址设置环境变量:

AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

然后使用以下命令向基于 WSL 的应用开放服务器的防火墙:

az postgres flexible-server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME \
    --rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
    --start-ip-address $AZ_WSL_IP_ADDRESS \
    --end-ip-address $AZ_WSL_IP_ADDRESS \
    --output tsv

配置 Azure Database for PostgreSQL 灵活服务器数据库

使用以下命令创建新数据库:

az postgres flexible-server db create \
    --resource-group $AZ_RESOURCE_GROUP \
    --database-name $AZ_DATABASE_NAME \
    --server-name $AZ_DATABASE_SERVER_NAME \
    --output tsv

创建 Azure Database for PostgreSQL 灵活服务器非管理员用户并授予权限

接下来创建一个非管理员用户,并为其授予对数据库的所有权限。

注意

可在“管理 Microsoft Entra 用户 - Azure Database for PostgreSQL 灵活服务器”中阅读有关管理 Azure Database for PostgreSQL 灵活服务器用户的更多详细信息。

创建一个名为 create_ad_user.sql 的 SQL 脚本用于创建非管理员用户。 添加以下内容,在本地保存该脚本:

cat << EOF > create_ad_user.sql
select * from pgaadauth_create_principal('$AZ_POSTGRESQL_AD_NON_ADMIN_USERNAME', false, false);
EOF

然后,使用以下命令运行该 SQL 脚本以创建 Microsoft Entra 非管理员用户:

psql "host=$AZ_DATABASE_SERVER_NAME.postgres.database.chinacloudapi.cn user=$CURRENT_USERNAME dbname=postgres port=5432 password=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken) sslmode=require" < create_ad_user.sql

现在使用以下命令删除临时 SQL 脚本文件:

rm create_ad_user.sql

新建一个 Java 项目

使用你偏好的 IDE 在 Java 8 或更高版本中创建新的 Java 项目,并在其根目录中添加一个包含以下内容的 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
      <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.3.6</version>
      </dependency>
      <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-identity-extensions</artifactId>
        <version>1.0.0</version>
      </dependency>
    </dependencies>
</project>

此文件是一个 Apache Maven,用于配置要使用的项目:

  • Java 8
  • 最新的用于 Java 的 PostgreSQL 驱动程序

准备用于连接到 Azure Database for PostgreSQL 灵活服务器的配置文件

创建 src/main/resources/application.properties 文件,然后添加以下内容:

cat << EOF > src/main/resources/application.properties
url=jdbc:postgresql://${AZ_DATABASE_SERVER_NAME}.postgres.database.chinacloudapi.cn:5432/${AZ_DATABASE_NAME}?sslmode=require&authenticationPluginClassName=com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin
user=${AZ_POSTGRESQL_AD_NON_ADMIN_USERNAME}
EOF

注意

配置属性 url 已附加 ?serverTimezone=UTC以命令 JDBC 驱动程序在连接到数据库时使用 TLS(传输层安全性)。 必须结合使用 TLS 与 Azure Database for PostgreSQL 灵活服务器,这是一个很好的安全做法。

创建 SQL 文件以生成数据库架构

你将使用 src/main/resources/schema.sql 文件来创建数据库架构。 创建包含以下内容的文件:

DROP TABLE IF EXISTS todo;
CREATE TABLE todo (id SERIAL PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BOOLEAN);

编写应用程序代码

连接到数据库

接下来添加 Java 代码,该代码使用 JDBC 在 Azure Database for PostgreSQL 灵活服务器实例中存储和检索数据。

创建 src/main/java/DemoApplication.java 文件并添加以下内容:

package com.example.demo;

import java.sql.*;
import java.util.*;
import java.util.logging.Logger;

public class DemoApplication {

    private static final Logger log;

    static {
        System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$-7s] %5$s %n");
        log =Logger.getLogger(DemoApplication.class.getName());
    }

    public static void main(String[] args) throws Exception {
        log.info("Loading application properties");
        Properties properties = new Properties();
        properties.load(DemoApplication.class.getClassLoader().getResourceAsStream("application.properties"));

        log.info("Connecting to the database");
        Connection connection = DriverManager.getConnection(properties.getProperty("url"), properties);
        log.info("Database connection test: " + connection.getCatalog());

        log.info("Create database schema");
        Scanner scanner = new Scanner(DemoApplication.class.getClassLoader().getResourceAsStream("schema.sql"));
        Statement statement = connection.createStatement();
        while (scanner.hasNextLine()) {
            statement.execute(scanner.nextLine());
        }

		/*
		Todo todo = new Todo(1L, "configuration", "congratulations, you have set up JDBC correctly!", true);
        insertData(todo, connection);
        todo = readData(connection);
        todo.setDetails("congratulations, you have updated data!");
        updateData(todo, connection);
        deleteData(todo, connection);
		*/

        log.info("Closing database connection");
        connection.close();
    }
}

此 Java 代码将使用前面创建的 application.properties 和 schema.sql 文件连接到 Azure Database for PostgreSQL 灵活服务器实例并创建用于存储数据的架构

在此文件中,你可以看到,我们注释了用于插入、读取、更新和删除数据的方法:我们将在本文的其余部分对这些方法进行编码,并且你将能够逐个取消注释。

注意

数据库凭据存储在“application.properties”文件的“user”和“password”属性中。 执行 DriverManager.getConnection(properties.getProperty("url"), properties); 时使用这些凭据,因为属性文件是作为参数传递的。

现在可以通过喜欢的工具执行此主类:

  • 使用你的 IDE,你应该能够右键单击 DemoApplication 类并执行它。
  • 使用 Maven,可以通过执行以下操作来运行应用程序:mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication"

应用程序应连接到 Azure Database for PostgreSQL 灵活服务器实例,创建数据库架构,然后关闭连接,如控制台日志中所示:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Closing database connection

创建域类

DemoApplication 类旁创建新的 Todo Java 类并添加以下代码:

package com.example.demo;

public class Todo {

    private Long id;
    private String description;
    private String details;
    private boolean done;

    public Todo() {
    }

    public Todo(Long id, String description, String details, boolean done) {
        this.id = id;
        this.description = description;
        this.details = details;
        this.done = done;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }

    @Override
    public String toString() {
        return "Todo{" +
                "id=" + id +
                ", description='" + description + '\'' +
                ", details='" + details + '\'' +
                ", done=" + done +
                '}';
    }
}

此类是在执行 schema.sql 脚本时创建的 todo 表上映射的域模型。

将数据插入 Azure Database for PostgreSQL 灵活服务器

src/main/java/DemoApplication.java 文件中,在 main 方法之后添加以下方法,以将数据插入数据库:

private static void insertData(Todo todo, Connection connection) throws SQLException {
    log.info("Insert data");
    PreparedStatement insertStatement = connection
            .prepareStatement("INSERT INTO todo (id, description, details, done) VALUES (?, ?, ?, ?);");

    insertStatement.setLong(1, todo.getId());
    insertStatement.setString(2, todo.getDescription());
    insertStatement.setString(3, todo.getDetails());
    insertStatement.setBoolean(4, todo.isDone());
    insertStatement.executeUpdate();
}

你现在可以对 main 方法中的以下两行执行取消注释操作:

Todo todo = new Todo(1L, "configuration", "congratulations, you have set up JDBC correctly!", true);
insertData(todo, connection);

现在,执行主类应会生成以下输出:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Closing database connection

从 Azure Database for PostgreSQL 灵活服务器读取数据

接下来,请阅读前面插入的数据,验证代码是否正常工作。

src/main/java/DemoApplication.java 文件中,在 insertData 方法之后添加以下方法,以从数据库中读取数据:

private static Todo readData(Connection connection) throws SQLException {
    log.info("Read data");
    PreparedStatement readStatement = connection.prepareStatement("SELECT * FROM todo;");
    ResultSet resultSet = readStatement.executeQuery();
    if (!resultSet.next()) {
        log.info("There is no data in the database!");
        return null;
    }
    Todo todo = new Todo();
    todo.setId(resultSet.getLong("id"));
    todo.setDescription(resultSet.getString("description"));
    todo.setDetails(resultSet.getString("details"));
    todo.setDone(resultSet.getBoolean("done"));
    log.info("Data read from the database: " + todo.toString());
    return todo;
}

你现在可以对 main 方法中的以下行执行取消注释操作:

todo = readData(connection);

现在,执行主类应会生成以下输出:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have set up JDBC correctly!', done=true}
[INFO   ] Closing database connection

更新 Azure Database for PostgreSQL 灵活服务器中的数据

让我们更新之前插入的数据。

src/main/java/DemoApplication.java 文件中,在 readData 方法之后添加以下方法,以更新数据库中的数据:

private static void updateData(Todo todo, Connection connection) throws SQLException {
    log.info("Update data");
    PreparedStatement updateStatement = connection
            .prepareStatement("UPDATE todo SET description = ?, details = ?, done = ? WHERE id = ?;");

    updateStatement.setString(1, todo.getDescription());
    updateStatement.setString(2, todo.getDetails());
    updateStatement.setBoolean(3, todo.isDone());
    updateStatement.setLong(4, todo.getId());
    updateStatement.executeUpdate();
    readData(connection);
}

你现在可以对 main 方法中的以下两行执行取消注释操作:

todo.setDetails("congratulations, you have updated data!");
updateData(todo, connection);

现在,执行主类应会生成以下输出:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have set up JDBC correctly!', done=true}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have updated data!', done=true}
[INFO   ] Closing database connection

删除 Azure Database for PostgreSQL 灵活服务器中的数据

最后,让我们删除之前插入的数据。

src/main/java/DemoApplication.java 文件中,在 updateData 方法之后添加以下方法,以删除数据库中的数据:

private static void deleteData(Todo todo, Connection connection) throws SQLException {
    log.info("Delete data");
    PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM todo WHERE id = ?;");
    deleteStatement.setLong(1, todo.getId());
    deleteStatement.executeUpdate();
    readData(connection);
}

你现在可以对 main 方法中的以下行执行取消注释操作:

deleteData(todo, connection);

现在,执行主类应会生成以下输出:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have set up JDBC correctly!', done=true}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have updated data!', done=true}
[INFO   ] Delete data
[INFO   ] Read data
[INFO   ] There is no data in the database!
[INFO   ] Closing database connection

清理资源

祝贺你! 你已创建了一个 Java 应用程序,该应用程序使用 JDBC 在 Azure Database for PostgreSQL 灵活服务器中存储和检索数据。

若要清理本快速入门中使用的所有资源,请使用以下命令删除该资源组:

az group delete \
    --name $AZ_RESOURCE_GROUP \
    --yes

后续步骤