杰瑞科技汇

Java如何高效查询MySQL数据库?

目录

  1. 准备工作
    • 安装 MySQL 数据库
    • 创建数据库和表
    • 准备 Java 开发环境
  2. 核心步骤详解
    • 第一步:添加 MySQL 驱动依赖
    • 第二步:建立数据库连接
    • 第三步:创建 StatementPreparedStatement
    • 第四步:执行查询
    • 第五步:处理结果集 (ResultSet)
    • 第六步:关闭资源
  3. 完整代码示例
    • 示例 1:使用 Statement (不推荐,仅用于理解)
    • 示例 2:使用 PreparedStatement (推荐,安全高效)
    • 示例 3:将查询结果封装到 Java 对象 (面向对象方式)
  4. 最佳实践与高级技巧
    • 必须使用 PreparedStatement:防止 SQL 注入
    • 使用 try-with-resources:自动管理资源
    • 使用连接池:提高性能
    • 处理大数据类型:如 BLOB, CLOB
    • 事务管理
  5. 常见问题与排错

准备工作

a. 安装 MySQL 数据库

确保你的系统上已经安装并运行了 MySQL 数据库,你可以从 MySQL 官网 下载并安装。

Java如何高效查询MySQL数据库?-图1
(图片来源网络,侵删)

b. 创建数据库和表

打开 MySQL 命令行客户端或使用如 Navicat, DBeaver 等图形化工具,执行以下 SQL 语句来创建一个示例数据库和表。

-- 创建一个名为 'testdb' 的数据库
CREATE DATABASE IF NOT EXISTS testdb;
-- 使用这个数据库
USE testdb;
-- 创建一个 'users' 表
CREATE TABLE IF NOT EXISTS users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL,
    age INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入一些测试数据
INSERT INTO users (username, email, age) VALUES
('zhangsan', 'zhangsan@example.com', 25),
('lisi', 'lisi@example.com', 30),
('wangwu', 'wangwu@example.com', 28);

c. 准备 Java 开发环境

确保你已经安装了 JDK 和一个 IDE(如 IntelliJ IDEA 或 Eclipse)。


核心步骤详解

第一步:添加 MySQL 驱动依赖

Java 程序需要 MySQL 的 JDBC 驱动才能与 MySQL 数据库通信,现在最主流的方式是使用 Maven 或 Gradle 来管理项目依赖。

Maven (pom.xml):pom.xml 文件中添加以下依赖:

Java如何高效查询MySQL数据库?-图2
(图片来源网络,侵删)
<dependencies>
    <!-- MySQL Connector/J 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version> <!-- 建议使用最新稳定版 -->
    </dependency>
</dependencies>

Gradle (build.gradle):build.gradle 文件中添加:

dependencies {
    // MySQL Connector/J 驱动
    implementation 'com.mysql:mysql-connector-j:8.0.33' // 建议使用最新稳定版
}

第二步:建立数据库连接

你需要数据库的 URL、用户名和密码来建立连接。

  • URL 格式: jdbc:mysql://[主机名]:[端口]/[数据库名]?[属性]

    • 主机名: 通常是 localhost0.0.1
    • 端口: MySQL 默认端口是 3306
    • 数据库名: 你要连接的数据库,如 testdb
    • 属性: useSSL=false (用于本地开发,禁用 SSL 加密) 或 useSSL=true (生产环境推荐)。serverTimezone=UTC 用于解决时区问题。
  • 示例代码:

    Java如何高效查询MySQL数据库?-图3
    (图片来源网络,侵删)
    String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
    String username = "root"; // 你的 MySQL 用户名
    String password = "your_password"; // 你的 MySQL 密码
    Connection connection = null;
    try {
        // 加载驱动 (对于新版本驱动,这步通常可以省略)
        Class.forName("com.mysql.cj.jdbc.Driver");
        // 建立连接
        connection = DriverManager.getConnection(url, username, password);
        System.out.println("数据库连接成功!");
    } catch (Exception e) {
        e.printStackTrace();
    }

第三步:创建 StatementPreparedStatement

连接建立后,你需要一个对象来执行 SQL 语句。

  • Statement: 用于执行静态的 SQL 语句。不推荐用于包含用户输入的查询,因为它极易受到 SQL 注入攻击。
  • PreparedStatement: 强烈推荐,它预编译 SQL 语句,并使用 作为占位符,你可以安全地设置参数,有效防止 SQL 注入,并且性能通常更好。

第四步:执行查询

调用 executeQuery() 方法来执行 SELECT 查询,这个方法会返回一个 ResultSet 对象。

String sql = "SELECT id, username, email, age FROM users";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);

第五步:处理结果集 (ResultSet)

ResultSet 就像一个指向查询结果数据的指针,你需要使用 next() 方法将指针移动到下一行,并使用 getXXX() 方法(如 getString(), getInt())来获取列的值。

while (resultSet.next()) { // 循环遍历每一行
    // 通过列名获取数据,更具可读性
    int id = resultSet.getInt("id");
    String username = resultSet.getString("username");
    String email = resultSet.getString("email");
    int age = resultSet.getInt("age");
    // 也可以通过列索引获取 (从1开始)
    // int id = resultSet.getInt(1);
    System.out.println("ID: " + id + ", 用户名: " + username + ", 邮箱: " + email + ", 年龄: " + age);
}

第六步:关闭资源

为了防止资源泄露(如数据库连接、内存占用),你必须按照创建的逆序关闭所有资源:ResultSet -> Statement -> Connection

if (resultSet != null) {
    try { resultSet.close(); } catch (SQLException e) { /* ... */ }
}
if (statement != null) {
    try { statement.close(); } catch (SQLException e) { /* ... */ }
}
if (connection != null) {
    try { connection.close(); } catch (SQLException e) { /* ... */ }
}

完整代码示例

示例 2:使用 PreparedStatement (推荐)

这是最常用、最安全的方式。

import java.sql.*;
public class JdbcPreparedStatementExample {
    // 数据库连接信息
    private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "your_password";
    public static void main(String[] args) {
        // 使用 try-with-resources 自动管理资源,无需手动关闭
        try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) {
            System.out.println("数据库连接成功!");
            // 1. 准备 SQL 语句,使用 ? 作为占位符
            String sql = "SELECT id, username, email, age FROM users WHERE age > ?";
            // 2. 创建 PreparedStatement 对象
            try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                // 3. 设置参数 (index 从 1 开始)
                preparedStatement.setInt(1, 26); // 设置第一个 ? 为 26
                // 4. 执行查询
                try (ResultSet resultSet = preparedStatement.executeQuery()) {
                    // 5. 处理结果集
                    System.out.println("年龄大于 26 的用户:");
                    while (resultSet.next()) {
                        int id = resultSet.getInt("id");
                        String username = resultSet.getString("username");
                        String email = resultSet.getString("email");
                        int age = resultSet.getInt("age");
                        System.out.printf("ID: %d, 用户名: %s, 邮箱: %s, 年龄: %d%n", id, username, email, age);
                    }
                }
            }
        } catch (SQLException e) {
            System.err.println("数据库操作出错!");
            e.printStackTrace();
        }
    }
}

示例 3:将查询结果封装到 Java 对象 (面向对象方式)

在实际项目中,我们通常会将数据库的一行数据映射到一个 Java 对象中,这样更符合面向对象的思想。

创建 User 实体类:

// User.java
public class User {
    private int id;
    private String username;
    private String email;
    private int age;
    // 构造方法、Getter 和 Setter
    public User() {}
    public User(int id, String username, String email, int age) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
    // 省略 Getter 和 Setter...
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

修改查询代码以返回 List<User>:

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class JdbcObjectMappingExample {
    private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "your_password";
    public static void main(String[] args) {
        String sql = "SELECT id, username, email, age FROM users";
        List<User> users = new ArrayList<>();
        try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
             PreparedStatement preparedStatement = connection.prepareStatement(sql);
             ResultSet resultSet = preparedStatement.executeQuery()) {
            while (resultSet.next()) {
                // 从结果集中取出数据,创建 User 对象
                User user = new User();
                user.setId(resultSet.getInt("id"));
                user.setUsername(resultSet.getString("username"));
                user.setEmail(resultSet.getString("email"));
                user.setAge(resultSet.getInt("age"));
                // 将 User 对象添加到 List 中
                users.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 打印结果
        System.out.println("所有用户:");
        for (User user : users) {
            System.out.println(user);
        }
    }
}

最佳实践与高级技巧

a. 必须使用 PreparedStatement

永远不要使用 Statement 来拼接 SQL 字符串来处理用户输入。PreparedStatement 通过预编译和参数绑定,从根本上杜绝了 SQL 注入的风险。

b. 使用 try-with-resources

从 Java 7 开始,try-with-resources 语句可以自动实现 AutoCloseable 接口的资源关闭,强烈推荐使用它,代码更简洁,也更能保证资源被正确关闭,避免泄露。

// 自动关闭 Connection, PreparedStatement, ResultSet
try (Connection con = ...;
     PreparedStatement ps = con.prepareStatement(...);
     ResultSet rs = ps.executeQuery()) {
    // ... do work ...
} // con, ps, rs 在这里会自动关闭

c. 使用连接池

每次创建和销毁数据库连接都是非常消耗性能的操作,在高并发应用中,必须使用连接池来复用连接。

  • 常用连接池: HikariCP (性能极佳,是目前的事实标准), Druid (阿里巴巴出品,功能强大,带有监控), C3P0。

  • HikariCP 配置示例 (Maven):

    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version>
    </dependency>
    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl("jdbc:mysql://localhost:3306/testdb");
    config.setUsername("root");
    config.setPassword("your_password");
    config.setDriverClassName("com.mysql.cj.jdbc.Driver");
    HikariDataSource dataSource = new HikariDataSource(config);
    // 从连接池获取连接
    try (Connection connection = dataSource.getConnection()) {
        // 使用 connection 进行数据库操作...
    }

d. 处理大数据类型

对于 BLOB (二进制数据,如图片) 或 CLOB (文本数据),需要使用 getInputStream()setBinaryStream() / setCharacterStream() 来流式处理,避免内存溢出。

e. 事务管理

默认情况下,每个 SQL 语句都是一个独立的事务,你可以手动控制事务的提交和回滚。

Connection connection = null;
try {
    connection = dataSource.getConnection();
    // 关闭自动提交,开启事务
    connection.setAutoCommit(false);
    // 执行多个 SQL 语句
    // statement1.executeUpdate(...);
    // statement2.executeUpdate(...);
    // 所有语句执行成功,提交事务
    connection.commit();
    System.out.println("事务提交成功!");
} catch (SQLException e) {
    // 发生异常,回滚事务
    if (connection != null) {
        try {
            connection.rollback();
            System.out.println("事务已回滚!");
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    e.printStackTrace();
} finally {
    if (connection != null) {
        try {
            // 恢复自动提交模式
            connection.setAutoCommit(true);
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

常见问题与排错

  • No suitable driver found for jdbc:mysql://...

    • 原因: MySQL 驱动依赖没有添加到项目中,或者 IDE 没有正确加载依赖。
    • 解决: 确保 pom.xmlbuild.gradle 中的依赖已正确配置,并刷新 Maven/Gradle 项目。
  • Access denied for user 'root'@'localhost'

    • 原因: 数据库用户名或密码错误。
    • 解决: 检查你的 Java 代码中 USERPASSWORD 是否与 MySQL 中的用户信息匹配。
  • Unknown database 'testdb'

    • 原因: 连接 URL 中的数据库名不存在。
    • 解决: 检查数据库名拼写是否正确,或者先在 MySQL 中创建该数据库。
  • Communications link failure

    • 原因: MySQL 服务未启动,或者网络不通(如防火墙阻止了 3306 端口)。
    • 解决: 确保 MySQL 服务正在运行,并且可以从你的 Java 应用程序所在机器访问到 MySQL 服务器的 3306 端口。

希望这份详细的指南能帮助你顺利地在 Java 中使用 MySQL 进行数据库查询!

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