当前位置:首页 > 后端开发 > 正文

java 怎么实现查询

Java可通过JDBC连接数据库,创建Statement对象执行SQL查询,遍历ResultSet获取数据;也可整合MyBatis等ORM

以下是关于 Java 实现数据库查询 的完整技术指南,涵盖核心原理、多种实现方式及最佳实践:


基础认知:Java 与数据库交互的本质

Java 通过 JDBC (Java DataBase Connectivity) 标准接口实现与关系型数据库的通信,其核心流程为:

  1. 建立连接 → 2. 创建语句对象 → 3. 执行 SQL 命令 → 4. 处理结果集 → 5. 释放资源
    此过程遵循「获取-操作-关闭」的资源管理模式,需特别注意异常处理和资源释放。

关键组件对照表

功能 JDBC 接口/类 作用
驱动管理器 DriverManager 注册/获取数据库驱动
数据库连接 Connection 代表与数据库的会话,可创建语句对象
执行 SQL 的载体 Statement/PreparedStatement 发送 SQL 指令至数据库
存储查询结果 ResultSet 二维网格结构,支持向前/向后遍历(仅限特定驱动)
数据集存取优化 ResultSetMetaData 动态获取列名、类型等信息,用于灵活解析未知结构的查询结果

主流实现方案详解

▶️ 方案 1:原生 JDBC + 手动管理(适合学习底层机制)

// 完整示例:查询 department 表中薪资 > 8000 的员工信息
import java.sql.;
public class JdbcDemo {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            // 1. 加载驱动(新版 JDBC 可省略此步)
            Class.forName("com.mysql.cj.jdbc.Driver"); // MySQL 8+ 驱动类名
            // 2. 建立连接(URL 含时区配置防警告)
            String url = "jdbc:mysql://localhost:3306/company?serverTimezone=UTC";
            conn = DriverManager.getConnection(url, "root", "password");
            // 3. 创建预编译语句(防 SQL 注入)
            String sql = "SELECT id, name, salary FROM employees WHERE salary > ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setDouble(1, 8000); // 设置第一个占位符的值
            // 4. 执行查询
            rs = pstmt.executeQuery();
            // 5. 遍历结果集
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                double salary = rs.getDouble("salary");
                System.out.printf("ID: %d | Name: %-10s | Salary: %.2f%n", id, name, salary);
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            // 6. 逆向顺序关闭资源(重点!)
            try { if (rs != null) rs.close(); } catch (SQLException ignored) {}
            try { if (pstmt != null) pstmt.close(); } catch (SQLException ignored) {}
            try { if (conn != null) conn.close(); } catch (SQLException ignored) {}
        }
    }
}

️ 注意事项

  • 永远在 finally 块中关闭资源,且关闭顺序应为 ResultSet → Statement → Connection
  • 优先使用 PreparedStatement:既防 SQL 注入,又提高重复执行效率(预编译机制)
  • 列名推荐使用常量维护:避免硬编码字符串导致的拼写错误
  • 大数据量分页处理:通过 LIMIT ?, ? 实现物理分页,而非一次性加载全部数据

▶️ 方案 2:Try-with-Resources 语法糖(Java 7+)

上述代码可简化为:

try (Connection conn = DriverManager.getConnection(url, user, pass);
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setXXX(index, value); // 设置参数
    try (ResultSet rs = pstmt.executeQuery()) {
        while (rs.next()) { / 处理结果 / }
    }
} // 自动关闭所有 AutoCloseable 资源

优势:无需显式在 finally 中关闭资源,代码更简洁且安全。

▶️ 方案 3:Spring JDBC Template(企业级封装)

Spring 对 JDBC 进行了深度包装,典型用法如下:

@Autowired
private JdbcTemplate jdbcTemplate; // Spring 提供的模板类
public List<Employee> findHighSalaryStaff(double threshold) {
    String sql = "SELECT id, name, salary FROM employees WHERE salary > ?";
    return jdbcTemplate.query(sql, new Object[]{threshold}, (rs, rowNum) -> {
        Employee emp = new Employee();
        emp.setId(rs.getInt("id"));
        emp.setName(rs.getString("name"));
        emp.setSalary(rs.getDouble("salary"));
        return emp;
    });
}

核心特性

  • 自动管理连接池(需配合 DataSource
  • 支持多样的结果集映射(单行映射、列表映射、流式处理)
  • 统一异常转换(将 SQLException 转为 DataAccessException)
  • 声明式事务管理(@Transactional 注解)

▶️ 方案 4:MyBatis(轻量级 ORM)

通过 XML 或注解定义 SQL 映射关系:

<!-UserMapper.xml -->
<select id="selectByDept" resultType="com.example.User">
    SELECT  FROM users WHERE department_id = #{deptId}
</select>

Java 调用:

SqlSession session = MyBatisUtil.getSqlSessionFactory().openSession();
try {
    List<User> users = session.selectList("selectByDept", 101);
} finally {
    session.close();
}

特点

  • SQL 写在外部文件,便于 DBA 审核和维护
  • 动态 SQL 功能强大(if/choose/foreach 标签)
  • 一级缓存(SqlSession 级别)和二级缓存(Namespace 级别)提升性能

▶️ 方案 5:Hibernate(全功能 ORM)

基于 JPA 规范实现,完全面向对象操作:

java 怎么实现查询  第1张

// HQL 查询示例(Hibernate Query Language)
String hql = "FROM Employee e WHERE e.salary > :threshold";
Query<Employee> query = session.createQuery(hql, Employee.class);
query.setParameter("threshold", 8000D);
List<Employee> results = query.list();

适用场景:复杂对象关系映射、跨数据库迁移需求较强的项目。


关键技巧与最佳实践

场景 解决方案
防止 SQL 注入 强制使用 PreparedStatement
禁止字符串拼接 SQL
批量插入/更新 使用 addBatch() + executeBatch(),比逐条执行快 5~10 倍
大文本字段处理 CLOB 类型对应 Clob 接口,通过 Reader 读写
BLOB 二进制数据处理 Blob 接口配合 InputStream,注意流式传输避免 OOM
敏感词过滤 可在业务层添加白名单校验,或使用数据库内置函数(如 REGEXP_REPLACE)
慢查询优化 EXPLAIN 分析执行计划 → 添加合适索引 → 避免全表扫描
连接池配置 HikariCP(目前最快):maximumPoolSize=10, connectionTimeout=30000

常见问题排查手册

Q1: java.sql.SQLException: Access denied for user ‘root’@’localhost’ (using password: YES)

原因:数据库用户名密码错误,或权限不足
解决

  • 检查配置文件中的用户名密码是否正确
  • 确认该用户有访问目标数据库的权限(GRANT ALL PRIVILEGES ON dbname TO ‘user’@’host’;)
  • 若使用远程连接,需放开防火墙端口(默认 MySQL 3306)

Q2: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

原因:网络中断或数据库服务未启动
解决

  • 检查数据库进程是否运行(systemctl status mysql
  • 测试网络连通性(telnet localhost 3306)
  • 检查 URL 中的 IP/端口是否正确
  • 若使用云数据库,确认白名单已添加应用服务器公网 IP

进阶方向建议

  1. 分布式事务:Seata 框架实现跨库事务一致性
  2. 读写分离:MyCat 中间件实现主从负载均衡
  3. NoSQL 融合:MongoDB 通过 Morphia 实现文档型数据操作
  4. 监控告警:Druid 监控面板实时查看 SQL 执行情况
  5. 压力测试:JMeter 模拟高并发场景验证系统稳定性

通过掌握以上技术要点,开发者可根据项目规模选择合适的持久层方案,从基础 JDBC 到成熟 ORM 框架均能游刃有余

0