杰瑞科技汇

Java如何从数据库获取数据?

JDBC (Java Database Connectivity)

无论你使用什么数据库(MySQL, PostgreSQL, Oracle, SQL Server 等),Java 提供的标准 API 都是 JDBC,你可以把它想象成一座连接 Java 应用程序和数据库的“桥梁”。

Java如何从数据库获取数据?-图1
(图片来源网络,侵删)

获取数据的通用流程如下:

  1. 加载驱动:告诉 JVM 你要使用哪个数据库的驱动程序。
  2. 建立连接:通过 URL、用户名和密码,与数据库建立一个通信通道。
  3. 创建语句:创建一个 StatementPreparedStatement 对象,用于执行 SQL 查询。
  4. 执行查询:执行 SQL 语句,并返回一个 ResultSet 对象,ResultSet 就像一个指向查询结果集的游标。
  5. 处理结果集:遍历 ResultSet,从中取出每一行数据,并转换成 Java 对象(如自定义实体类、Map 等)。
  6. 关闭资源:按照“后开先关”的原则,依次关闭 ResultSetStatementConnection

传统 JDBC 方式(不推荐用于生产)

这是最基础、最原始的方式,能帮助你理解底层原理。但在实际项目中,我们不推荐直接使用,因为它代码冗长、繁琐且容易出错(比如忘记关闭资源)。

步骤详解

  1. 准备数据库驱动

    • 下载你所用数据库的 JDBC 驱动 JAR 包(MySQL 的 mysql-connector-j-x.x.x.jar)。
    • 将 JAR 包添加到你的项目的类路径(Classpath)中,如果你使用 Maven 或 Gradle,只需在 pom.xmlbuild.gradle 中添加依赖即可。

    Maven 依赖示例 (MySQL):

    Java如何从数据库获取数据?-图2
    (图片来源网络,侵删)
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version> <!-- 使用你需要的版本 -->
    </dependency>
  2. 编写 Java 代码

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    public class JdbcExample {
        // 数据库连接信息
        private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC";
        private static final String USER = "your_username";
        private static final String PASS = "your_password";
        public static void main(String[] args) {
            // try-with-resources 语句,可以自动关闭资源,是 Java 7+ 的最佳实践
            try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
                 Statement stmt = conn.createStatement();
                 ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users")) {
                // 4. 处理结果集
                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 (SQLException e) {
                e.printStackTrace();
            }
            // Connection, Statement, ResultSet 会在 try 块结束时自动关闭
        }
    }

使用 try-with-resources 优化(推荐)

上面的代码已经使用了 try-with-resources,这是对传统 JDBC 最重要的优化,它能确保 Connection, Statement, ResultSet 等实现了 AutoCloseable 接口的资源在使用完毕后自动关闭,即使发生异常也不会导致资源泄漏。


使用 PreparedStatement 防止 SQL 注入(必备技能)

当 SQL 查询包含用户输入时,必须使用 PreparedStatement 来防止 SQL 注入攻击,它预编译 SQL 语句,然后将参数作为变量传入,数据库引擎不会将其解释为 SQL 代码。

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class PreparedStatementExample {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC";
    private static final String USER = "your_username";
    private static final String PASS = "your_password";
    public List<String> findUsersByName(String nameKeyword) {
        List<String> userList = new ArrayList<>();
        // 使用 ? 作为占位符
        String sql = "SELECT name FROM users WHERE name LIKE ?";
        // try-with-resources 确保 Connection, PreparedStatement, ResultSet 自动关闭
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数,索引从 1 开始
            pstmt.setString(1, "%" + nameKeyword + "%");
            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    userList.add(rs.getString("name"));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return userList;
    }
}

使用连接池(生产环境标准)

每次获取数据库连接都创建一个新的,开销很大,连接池(Connection Pool)可以复用已经建立的连接,大大提高性能。

Java如何从数据库获取数据?-图3
(图片来源网络,侵删)
  • HikariCP: 目前性能最好、最流行的连接池。
  • Druid: 阿里开源,功能强大,带有监控功能。

使用 HikariCP 的示例:

  1. 添加 Maven 依赖

    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version> <!-- 使用最新版本 -->
    </dependency>
  2. 配置并使用连接池

    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    public class DataSourceExample {
        // 1. 创建并配置数据源
        private static HikariDataSource dataSource;
        static {
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl("jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC");
            config.setUsername("your_username");
            config.setPassword("your_password");
            config.setDriverClassName("com.mysql.cj.jdbc.Driver");
            // 连接池优化配置 (可选)
            config.setMaximumPoolSize(10);
            config.setMinimumIdle(5);
            config.setConnectionTimeout(30000); // 30 seconds
            config.setIdleTimeout(600000); // 10 minutes
            config.setMaxLifetime(1800000); // 30 minutes
            dataSource = new HikariDataSource(config);
        }
        public List<User> getAllUsers() {
            List<User> users = new ArrayList<>();
            String sql = "SELECT id, name, email FROM users";
            // try-with-resources 从连接池获取连接
            try (Connection conn = dataSource.getConnection();
                 Statement stmt = conn.createStatement();
                 ResultSet rs = stmt.executeQuery(sql)) {
                while (rs.next()) {
                    User user = new User();
                    user.setId(rs.getInt("id"));
                    user.setName(rs.getString("name"));
                    user.setEmail(rs.getString("email"));
                    users.add(user);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return users;
        }
        // 假设的 User 类
        static class User {
            private int id;
            private String name;
            private String email;
            // Getters and Setters...
        }
    }

使用 ORM 框架(现代企业级开发首选)

对象关系映射框架让你可以用面向对象的方式来操作数据库,而不用写繁琐的 SQL 语句,框架会自动将 Java 对象映射到数据库表,并处理增删改查。

  • MyBatis: SQL 与代码分离,SQL 语句写在 XML 文件中,灵活性高。
  • Hibernate (JPA): 全自动 ORM,非常强大,但有时会显得“黑盒”。
  • Spring Data JPA: 在 Hibernate 基础上封装,提供了极其简单的 Repository 接口,只需定义接口方法名即可实现查询,是 Spring Boot 生态中的绝对主流。

Spring Data JPA 示例 (最简单、最推荐)

这是目前 Java Web 开发中最主流、最高效的方式。

  1. 添加依赖 (Spring Boot 项目)

    <!-- Spring Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
  2. 配置 application.properties

    spring.datasource.url=jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC
    spring.datasource.username=your_username
    spring.datasource.password=your_password
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    # JPA/Hibernate 配置
    spring.jpa.hibernate.ddl-auto=update # 或 validate, create, create-drop
    spring.jpa.show-sql=true # 在控制台打印 SQL
    spring.jpa.properties.hibernate.format_sql=true # 格式化 SQL
  3. 创建实体类

    import javax.persistence.*;
    @Entity // 声明这是一个 JPA 实体
    @Table(name = "users") // 对应数据库中的 users 表
    public class User {
        @Id // 声明主键
        @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主键
        private Long id;
        @Column(name = "name") // 对应 name 列
        private String name;
        @Column(name = "email")
        private String email;
        // Getters and Setters...
    }
  4. 创建 Repository 接口

    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    import java.util.List;
    @Repository // 声明这是一个 Spring Bean
    public interface UserRepository extends JpaRepository<User, Long> {
        // Spring Data JPA 会自动为你实现这个方法!
        // 根据方法名自动生成 SQL: SELECT * FROM users WHERE name LIKE ?%
        List<User> findByNameStartingWith(String namePrefix);
    }
  5. 在 Service 中使用

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import java.util.List;
    @Service
    public class UserService {
        @Autowired
        private UserRepository userRepository;
        public List<User> getAllUsers() {
            // findAll() 是 JpaRepository 提供的内置方法
            return userRepository.findAll();
        }
        public List<User> findUsersByName(String prefix) {
            // 直接调用我们自己定义的方法
            return userRepository.findByNameStartingWith(prefix);
        }
    }

总结与建议

方式 优点 缺点 适用场景
传统 JDBC 无需额外依赖,理解底层原理 代码繁琐,易出错,性能低 学习 JDBC 原理,简单脚本
PreparedStatement 防止 SQL 注入,是必备技能 仍需手动管理资源 所有需要拼接 SQL 的场景
连接池 大幅提升性能,复用连接 需要额外配置和管理 所有生产环境
ORM 框架 开发效率高,代码简洁,面向对象 学习曲线,有一定性能开销,SQL 灵活性降低 现代企业级应用开发

给新手的建议:

  1. try-with-resourcesPreparedStatement 开始,这是写健壮 JDBC 代码的基础。
  2. 立刻使用连接池,HikariCP,这是生产环境的标配。
  3. 直接学习 Spring Data JPA,如果你使用 Spring Boot,这是最高效、最主流的选择,能让你从繁琐的 JDBC 代码中解放出来,专注于业务逻辑。
分享:
扫描分享到社交APP
上一篇
下一篇