杰瑞科技汇

Java如何高效连接SQL数据库?

我会按照以下结构来讲解,确保你从基础到实践都能理解:

Java如何高效连接SQL数据库?-图1
(图片来源网络,侵删)
  1. 核心概念:什么是 JDBC?
  2. 连接数据库的步骤(通用流程)
  3. 实战示例:连接 MySQL 数据库
  4. 实战示例:连接 PostgreSQL 数据库
  5. 最佳实践:使用 try-with-resources
  6. 最佳实践:使用连接池 (如 HikariCP)

核心概念:什么是 JDBC?

JDBC 是 Java 语言中用来规范客户端程序如何访问数据库的应用程序接口,它提供了查询和更新数据库中数据的方法。JDBC 是 Java 和数据库之间的桥梁

JDBC 本身只是一套规范(接口),数据库厂商(如 Oracle, MySQL, PostgreSQL)需要实现这套规范,提供我们称之为 JDBC 驱动 的具体实现类,我们的 Java 程序就是通过加载这些驱动来连接特定数据库的。


连接数据库的通用步骤

无论你使用哪种 SQL 数据库,连接的步骤基本都遵循以下模式:

  1. 加载 JDBC 驱动:在早期版本中,需要显式地加载驱动类(Class.forName(...)),在现代 JDBC (4.0+) 中,驱动会自动注册,这一步通常可以省略。
  2. 获取数据库连接:使用 DriverManager 类的 getConnection() 方法,提供数据库的 URL、用户名和密码来创建一个 Connection 对象。
  3. 创建 Statement 对象:通过 Connection 对象创建一个 StatementPreparedStatement 对象,用于执行 SQL 语句。
  4. 执行 SQL 语句:使用 Statement 对象的 executeQuery() (用于查询) 或 executeUpdate() (用于更新/插入/删除) 方法来执行 SQL。
  5. 处理结果集:如果执行的是查询语句,会返回一个 ResultSet 对象,你需要遍历这个对象来获取查询结果。
  6. 关闭资源:在 finally 块或使用 try-with-resources 语句中,按顺序关闭 ResultSetStatementConnection,以释放数据库资源。

实战示例:连接 MySQL 数据库

这是最常见的情况之一,我们将使用 Maven 来管理项目依赖,因为它能自动下载 JDBC 驱动。

Java如何高效连接SQL数据库?-图2
(图片来源网络,侵删)

步骤 1:添加 MySQL JDBC 驱动依赖

在你的 pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- MySQL Connector/J 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version> <!-- 建议使用最新稳定版 -->
    </dependency>
</dependencies>

步骤 2:编写 Java 连接代码

假设你的 MySQL 数据库信息如下:

  • 主机: localhost
  • 端口: 3306
  • 数据库名: test_db
  • 用户名: root
  • 密码: your_password
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class MySqlConnectionExample {
    // 数据库连接信息
    private static final String DB_URL = "jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASS = "your_password";
    public static void main(String[] args) {
        // 1. 加载驱动 (JDBC 4.0+ 后可省略,但显式写出更清晰)
        // try {
        //     Class.forName("com.mysql.cj.jdbc.Driver");
        // } catch (ClassNotFoundException e) {
        //     e.printStackTrace();
        //     return;
        // }
        // Connection, Statement, ResultSet 都需要关闭,所以我们在外部定义
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 2. 获取数据库连接
            System.out.println("正在连接到数据库...");
            conn = DriverManager.getConnection(DB_URL, USER, PASS);
            System.out.println("数据库连接成功!");
            // 3. 创建 Statement 对象
            stmt = conn.createStatement();
            // 4. 执行 SQL 查询
            String sql = "SELECT id, name, age FROM users";
            rs = stmt.executeQuery(sql);
            // 5. 处理结果集
            System.out.println("ID\tName\tAge");
            while (rs.next()) {
                // 通过列名或列索引获取数据
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                // 输出数据
                System.out.println(id + "\t" + name + "\t" + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6. 关闭资源
            // 关闭的顺序很重要:先关闭 ResultSet,再 Statement,Connection
            try {
                if (rs != null) rs.close();
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
                System.out.println("数据库连接已关闭。");
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

代码解释:

  • DB_URL: 数据库的统一资源定位符。
    • jdbc:mysql://: 协议和子协议,表示使用 MySQL 的 JDBC 连接。
    • localhost:3306: 主机和端口。
    • /test_db: 数据库名。
    • ?useSSL=false: 禁用 SSL(本地开发时常用)。
    • &serverTimezone=UTC: 设置服务器时区,避免警告。
  • DriverManager.getConnection(): 核心方法,用于建立连接。
  • conn.createStatement(): 创建一个 Statement 对象,用于执行静态 SQL 语句。
  • stmt.executeQuery(sql): 执行查询,返回一个 ResultSet 对象。
  • rs.next(): 将光标从当前位置向下移动一行,并判断是否有下一行数据。
  • rs.getXXX(): 从 ResultSet 中获取数据,XXX 是数据类型(如 String, Int, Date 等)。

实战示例:连接 PostgreSQL 数据库

过程几乎完全相同,只需要更换驱动和 URL。

Java如何高效连接SQL数据库?-图3
(图片来源网络,侵删)

步骤 1:添加 PostgreSQL JDBC 驱动依赖

pom.xml 中添加:

<dependencies>
    <!-- PostgreSQL JDBC 驱动 -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.6.0</version> <!-- 建议使用最新稳定版 -->
    </dependency>
</dependencies>

步骤 2:编写 Java 连接代码

假设你的 PostgreSQL 数据库信息如下:

  • 主机: localhost
  • 端口: 5432
  • 数据库名: testdb
  • 用户名: postgres
  • 密码: your_password
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PostgresConnectionExample {
    private static final String DB_URL = "jdbc:postgresql://localhost:5432/testdb";
    private static final String USER = "postgres";
    private static final String PASS = "your_password";
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            System.out.println("正在连接到 PostgreSQL 数据库...");
            // PostgreSQL 驱动加载方式
            Class.forName("org.postgresql.Driver");
            conn = DriverManager.getConnection(DB_URL, USER, PASS);
            System.out.println("数据库连接成功!");
            stmt = conn.createStatement();
            String sql = "SELECT id, name, email FROM employees";
            rs = stmt.executeQuery(sql);
            System.out.println("ID\tName\tEmail");
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "\t" + name + "\t" + email);
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null) rs.close();
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
                System.out.println("数据库连接已关闭。");
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

主要区别:

  • 驱动类名: org.postgresql.Driver
  • URL 格式: jdbc:postgresql://...
  • PostgreSQL 驱动通常需要显式加载 Class.forName

最佳实践:使用 try-with-resources

手动关闭资源(try-catch-finally)代码冗长且容易出错,从 Java 7 开始,推荐使用 try-with-resources 语句,它可以自动实现资源的关闭。

优点:

  • 代码更简洁。
  • 自动关闭:只要实现了 AutoCloseable 接口(Connection, Statement, ResultSet 都实现了),资源会在 try 块执行完毕后自动关闭,即使发生异常。
  • 关闭顺序:会按照声明的相反顺序自动关闭。

重构后的代码(以 MySQL 为例):

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ModernJdbcExample {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASS = "your_password";
    public static void main(String[] args) {
        // try-with-resources 会自动关闭 conn, stmt, rs
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM users")) {
            System.out.println("数据库连接成功!");
            System.out.println("ID\tName\tAge");
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println(id + "\t" + name + "\t" + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // conn, stmt, rs 都已经被自动关闭了
        System.out.println("资源已自动释放。");
    }
}

这个版本更健壮、更易于维护,是现代 Java 开发的标准做法。


最佳实践:使用连接池

每次执行数据库操作都创建和销毁连接是非常消耗性能的,在实际生产环境中,我们使用 数据库连接池 来管理连接。

连接池是一个预先创建好并维护一定数量数据库连接的容器,当需要连接时,从池中获取一个用完后,再归还给池,而不是销毁。

为什么使用连接池?

  • 性能提升:避免了频繁创建和销毁连接的开销。
  • 资源复用:连接被多个请求复用。
  • 控制并发:可以限制最大连接数,防止数据库因过多连接而崩溃。

流行的连接池:

  • HikariCP: 目前性能最好的连接池,被 Spring Boot 2.x+ 默认采用。
  • Apache DBCP: 一个老牌的连接池实现。
  • C3P0: 另一个广泛使用的连接池。

使用 HikariCP 的示例:

步骤 1:添加 HikariCP 依赖

<dependencies>
    <!-- HikariCP 连接池 -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version> <!-- 建议使用最新稳定版 -->
    </dependency>
    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>

步骤 2:编写代码

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 HikariCPExample {
    public static void main(String[] args) {
        // 1. 配置 HikariCP
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC");
        config.setUsername("root");
        config.setPassword("your_password");
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");
        // 连接池配置(可选)
        config.setMaximumPoolSize(10); // 最大连接数
        config.setMinimumIdle(5);      // 最小空闲连接数
        config.setConnectionTimeout(30000); // 连接超时时间 (毫秒)
        // 2. 创建数据源
        HikariDataSource dataSource = new HikariDataSource(config);
        try (Connection conn = dataSource.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM users")) {
            System.out.println("从连接池成功获取连接!");
            System.out.println("ID\tName\tAge");
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println(id + "\t" + name + "\t" + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 注意:通常应用程序生命周期内 dataSource 不会关闭
        // dataSource.close(); // 在应用关闭时调用
    }
}

场景 关键点 推荐做法
学习/简单脚本 代码简单,直接连接 使用 try-with-resources + DriverManager
生产环境/应用 性能、稳定性、并发性 使用连接池 (如 HikariCP) + try-with-resources
ORM 框架 (如 MyBatis, Hibernate) 框架封装了 JDBC 通常由框架内部管理连接池,开发者无需直接操作 Connection

希望这份详细的指南能帮助你掌握 Java 连接 SQL 数据库的核心知识!

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