杰瑞科技汇

postgresql java连接

目录

  1. 环境准备

    postgresql java连接-图1
    (图片来源网络,侵删)
    • 安装 PostgreSQL 数据库
    • 创建测试数据库和用户
    • 准备 Java 开发环境
    • 添加 PostgreSQL JDBC 驱动依赖
  2. 核心代码示例

    • 获取数据库连接
    • 执行查询 (SELECT)
    • 执行更新 (INSERT, UPDATE, DELETE)
    • 使用 try-with-resources 确保资源关闭
  3. 使用连接池 (推荐)

    • 为什么需要连接池?
    • 使用 HikariCP (目前性能最好的连接池)
    • 连接池示例代码
  4. 最佳实践与注意事项

    • 永远不要硬编码密码
    • 永远不要手动关闭连接 (连接池会处理)
    • 使用 PreparedStatement 防止 SQL 注入
    • 正确处理异常

环境准备

a. 安装 PostgreSQL 数据库

如果您还没有安装 PostgreSQL,请从 PostgreSQL 官方网站 下载并安装,安装过程中会要求您设置一个超级用户(通常是 postgres)的密码。

postgresql java连接-图2
(图片来源网络,侵删)

b. 创建测试数据库和用户

为了方便测试,我们创建一个新的数据库和一个专门用于应用连接的用户。

  1. 打开终端或命令提示符。

  2. 使用 psql 连接到 PostgreSQL:

    psql -U postgres

    (系统可能会要求您输入 postgres 用户的密码)

    postgresql java连接-图3
    (图片来源网络,侵删)
  3. psql 中执行以下 SQL 命令:

    -- 创建一个名为 'java_test_db' 的数据库
    CREATE DATABASE java_test_db;
    -- 创建一个新用户 'java_app_user',并设置密码
    CREATE USER java_app_user WITH PASSWORD 'your_strong_password';
    -- 将新用户对新数据库的所有权限授予
    GRANT ALL PRIVILEGES ON DATABASE java_test_db TO java_app_user;
    -- (可选) 将 'public' schema 的所有权限也授予该用户,方便操作
    GRANT ALL ON SCHEMA public TO java_app_user;

    您的测试环境就准备好了。

c. 准备 Java 开发环境

您需要一个 Java 开发环境,可以使用:

  • IDE:如 IntelliJ IDEA, Eclipse, VS Code。
  • 构建工具:如 Maven 或 Gradle。强烈推荐使用构建工具,它们可以自动管理依赖。

d. 添加 PostgreSQL JDBC 驱动依赖

这是最关键的一步,您需要将 PostgreSQL 的 JDBC 驱动程序(JDBC Driver,也称为 JDBC Driver 或 JDBC4 Driver)添加到您的项目中。

使用 Maven (pom.xml)

在您的 pom.xml 文件的 <dependencies> 标签中添加以下内容:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <!-- 
     使用最新的稳定版本是一个好习惯。
     您可以在 Maven Central 搜索 "postgresql" 来找到最新版本。
     截至 2025 年底,42.6.x 是一个非常流行的版本。
    -->
    <version>42.6.0</version> 
</dependency>

使用 Gradle (build.gradle)

在您的 build.gradle 文件的 dependencies 代码块中添加:

dependencies {
    // 同样,推荐使用最新版本
    implementation 'org.postgresql:postgresql:42.6.0'
}

添加依赖后,您的构建工具会自动下载所需的 JAR 文件。


核心代码示例

下面是使用 JDBC 连接 PostgreSQL 并执行基本操作的完整代码示例。

a. 获取数据库连接

我们需要一个 Connection 对象来与数据库建立连接。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class PostgresJdbcExample {
    // 数据库连接信息 - 建议从配置文件中读取,不要硬编码!
    private static final String DB_URL = "jdbc:postgresql://localhost:5432/java_test_db";
    private static final String USER = "java_app_user";
    private static final String PASS = "your_strong_password";
    public static void main(String[] args) {
        // try-with-resources 语句会自动关闭 Connection 对象
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS)) {
            if (conn != null) {
                System.out.println("成功连接到 PostgreSQL 数据库!");
                // 在这里执行数据库操作
                // createAndPopulateTable(conn);
                // selectData(conn);
            } else {
                System.out.println("连接失败!");
            }
        } catch (SQLException e) {
            System.err.println("数据库连接错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

代码解释:

  • DB_URL: JDBC URL 的格式为 jdbc:postgresql://<host>:<port>/<database_name>
  • USER: 连接数据库的用户名。
  • DriverManager.getConnection(): 这是获取连接的标准方法。
  • try-with-resources: 这是一个 Java 7+ 的特性,它会自动调用 conn.close(),即使发生异常也能确保资源被释放,强烈推荐使用

b. 执行查询

下面是一个查询 users 表的示例,我们需要在数据库中创建一个表:

-- 在 psql 中执行
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');

编写 Java 代码来查询这个表:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PostgresJdbcExample {
    // ... (DB_URL, USER, PASS 常量)
    public static void selectData(Connection conn) {
        // SQL 查询语句
        String sql = "SELECT id, name, email, created_at FROM users";
        // try-with-resources 确保 Statement 和 ResultSet 被关闭
        try (Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            System.out.println("\n--- 用户列表 ---");
            // 遍历结果集
            while (rs.next()) {
                // 通过列名获取数据,更具可读性和健壮性
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                java.sql.Timestamp createdAt = rs.getTimestamp("created_at");
                System.out.printf("ID: %d, Name: %s, Email: %s, Created At: %s%n",
                        id, name, email, createdAt);
            }
        } catch (SQLException e) {
            System.err.println("查询数据时出错: " + e.getMessage());
        }
    }
    // ... main 方法 ...
}

c. 执行更新

使用 PreparedStatement 来执行插入、更新和删除操作,这是防止 SQL 注入的最佳实践。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class PostgresJdbcExample {
    // ... (DB_URL, USER, PASS 常量)
    public static void insertUser(Connection conn, String name, String email) {
        // 使用 ? 作为占位符
        String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数,索引从 1 开始
            pstmt.setString(1, name);
            pstmt.setString(2, email);
            // 执行更新
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                System.out.println("成功插入新用户: " + name);
            } else {
                System.out.println("插入用户失败。");
            }
        } catch (SQLException e) {
            System.err.println("插入数据时出错: " + e.getMessage());
        }
    }
    // ... main 方法 ...
}

使用连接池 (强烈推荐)

在真实的应用程序中,为每个请求都创建和销毁数据库连接是非常低效的,连接池(Connection Pool)可以在应用程序启动时预先创建一组数据库连接,并重复使用它们,从而大大提高性能。

HikariCP 是目前公认性能最好、最可靠的 JDBC 连接池实现。

a. 添加 HikariCP 依赖

Maven (pom.xml):

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version> <!-- 使用最新版本 -->
</dependency>

Gradle (build.gradle):

implementation 'com.zaxxer:HikariCP:5.0.1'

b. 连接池示例代码

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PostgresWithHikariCP {
    // HikariCP 数据源
    private static HikariDataSource dataSource;
    // 静态代码块,在类加载时初始化连接池
    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:postgresql://localhost:5432/java_test_db");
        config.setUsername("java_app_user");
        config.setPassword("your_strong_password");
        // 连接池优化配置 (可根据实际情况调整)
        config.setDriverClassName("org.postgresql.Driver");
        config.setMaximumPoolSize(10); // 最大连接数
        config.setMinimumIdle(5);      // 最小空闲连接数
        config.setConnectionTimeout(30000); // 连接超时时间 (毫秒)
        config.setIdleTimeout(600000);     // 空闲连接超时时间 (毫秒)
        config.setMaxLifetime(1800000);    // 连接最大存活时间 (毫秒)
        dataSource = new HikariDataSource(config);
    }
    public static void main(String[] args) {
        // 从连接池获取连接
        try (Connection conn = dataSource.getConnection()) {
            System.out.println("从连接池成功获取连接!");
            // 执行查询
            try (Statement stmt = conn.createStatement();
                 ResultSet rs = stmt.executeQuery("SELECT name FROM users")) {
                while (rs.next()) {
                    System.out.println("User: " + rs.getString("name"));
                }
            }
        } catch (SQLException e) {
            System.err.println("从连接池获取连接或执行查询时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
    // 应用程序关闭时,关闭数据源
    public static void closeDataSource() {
        if (dataSource != null && !dataSource.isClosed()) {
            dataSource.close();
        }
    }
}

代码解释:

  1. HikariConfig: 用于配置连接池的各种参数。
  2. HikariDataSource: 是连接池的核心,我们只创建一个实例,并在整个应用中复用它。
  3. dataSource.getConnection(): 从连接池中获取一个连接,这个过程非常快,因为连接已经被预先创建好了。
  4. try-with-resources: 同样适用,当 conn.close() 被调用时,连接不会被真正关闭,而是被返回到连接池中,以供后续使用。
  5. closeDataSource(): 在应用程序(如 Web 服务器)关闭时,调用此方法来关闭整个连接池,释放所有资源。

最佳实践与注意事项

  1. 永远不要硬编码密码 将数据库连接信息(URL, 用户名, 密码)硬编码在代码中是非常危险的,应该使用外部配置文件(如 application.properties)、环境变量或专门的配置中心来管理。

  2. 永远不要手动关闭连接 (当使用连接池时) 使用连接池时,调用 connection.close() 的目的是将连接归还给池,而不是销毁它,如果您手动关闭了连接,池将不知道这一点,可能导致池中的连接计数错误。

  3. 始终使用 PreparedStatement 对于所有包含用户输入的 SQL 查询,都必须使用 PreparedStatement,它可以对输入进行转义,有效防止 SQL 注入攻击,即使是静态 SQL,使用 PreparedStatement 通常也更高效,因为它可以被数据库预编译和缓存。

  4. 正确处理异常 SQLException 是一个检查型异常,必须被处理或声明抛出,在 catch 块中,至少应该打印出异常信息(e.printStackTrace() 或使用日志框架),以便于调试。

  5. 使用日志框架 在生产环境中,不要使用 System.out.println,应该使用像 SLF4J + Logback 或 Log4j2 这样的日志框架,它们提供了更强大的日志管理功能(如日志级别、文件输出等)。

  6. 配置合理的连接池大小 连接池的大小不是越大越好,它应该根据您的数据库服务器的性能、应用的并发量以及每个 SQL 查询的平均耗时来调整,一个常用的经验公式是:((core_count * 2) + effective_spindle_count),但最佳值通常需要通过压力测试来确定。

分享:
扫描分享到社交APP
上一篇
下一篇