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

java怎么从数据库获取数据

使用JDBC:1. 导入驱动包;2. 获取Connection对象;3. 创建Statement/PreparedStatement;4. 执行executeQuery()获取ResultSet;5. 遍历结果集读取

核心技术体系

Java与数据库交互的核心依赖于JDBC(Java Database Connectivity)标准接口,该规范定义了一套统一的API用于连接各类关系型数据库,实际开发中需结合以下组件协同工作:

| 层级 | 作用 | 典型代表 |

|————-|——————————-|—————————|

| 驱动层 | 实现JDBC接口的具体数据库适配 | MySQL Connector/J |

| 连接管理层 | 维护数据库物理连接 | Druid/HikariCP连接池 |

| SQL执行层 | 解析并执行SQL语句 | Statement/PreparedStatement|

| 结果处理层 | 封装查询结果 | ResultSet/实体对象映射 |

| ORM层 | 对象-关系映射 | MyBatis/Hibernate/JPA |


基础实现流程(基于纯JDBC)

环境准备

  • 添加依赖:根据目标数据库选择对应驱动包(如mysql-connector-java-8.0.xx.jar)
  • 注册驱动:通过Class.forName("com.mysql.cj.jdbc.Driver")显式加载驱动类
  • 构建连接URL:格式为jdbc:mysql://host:port/dbname?useSSL=false&serverTimezone=UTC

标准操作五步曲

// 1. 加载驱动(新版JDBC可省略此步) Class.forName("com.mysql.cj.jdbc.Driver"); // 2. 建立连接 Connection conn = DriverManager.getConnection(url, user, password); // 3. 创建执行器(推荐使用PreparedStatement防SQL载入) String sql = "SELECT FROM users WHERE age > ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, 18); // 设置参数值 // 4. 执行查询 ResultSet rs = pstmt.executeQuery(); // 5. 遍历结果集 while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("username"); // ...其他字段处理 } // 6. 释放资源(务必按反向顺序关闭) rs.close(); pstmt.close(); conn.close();

关键注意事项

风险点 解决方案
SQL载入漏洞 强制使用PreparedStatement

禁止字符串拼接SQL

空指针异常 调用rs.getXXX()前先用rs.wasNull()判断
大数据量内存溢出 启用流式读取(statement.setFetchSize(Integer.MIN_VALUE))
字符编码问题 ️ URL参数添加characterEncoding=UTF-8
事务控制缺失 conn.setAutoCommit(false) + 手动提交/回滚


连接池优化方案

生产环境必须使用连接池替代直连模式,主流实现对比如下:

| 特性 | Druid | HikariCP | C3P0 |

|———————|——————————–|——————————|—————————|

| 性能表现 | | (目前最快) | |

| 监控功能 | 内置Web监控面板 | 基础指标 | 较弱 |

| 配置复杂度 | 中等 | 极简(默认配置即可生效) | 较高 |

| 特殊功能 | SQL防火墙/慢查询日志 | 无感集成Spring Boot | JMX支持 |

java怎么从数据库获取数据 第1张

Druid配置示例

# application.properties spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 连接池核心参数 spring.datasource.initial-size=5 spring.datasource.max-active=20 spring.datasource.min-idle=5 spring.datasource.max-wait=60000 # 超时时间毫秒


ORM框架应用实践

MyBatis基础用法

Mapper接口定义

java怎么从数据库获取数据 第2张

XML映射文件

<!-UserMapper.xml --> <select id="selectById" resultType="com.example.User"> SELECT FROM users WHERE id = #{id} </select> <select id="selectAll" resultMap="userMap"> SELECT u., r.role_name AS roleName FROM users u LEFT JOIN roles r ON u.role_id = r.id </select>

动态SQL示例

java怎么从数据库获取数据 第3张

<select id="findUsers" parameterType="map" resultType="User"> SELECT FROM users <where> <if test="name != null">AND name LIKE CONCAT('%',#{name},'%')</if> <if test="minAge != null">AND age >= #{minAge}</if> </where> ORDER BY create_time DESC <if test="startIndex != null and pageSize != null"> LIMIT #{startIndex},#{pageSize} </if> </select>

JPA/Hibernate核心概念

术语 说明 示例用法
@Entity 标识持久化类 @Entity(name="users")
@Table 指定表名/约束 @Table(uniqueConstraints=...)
@Column 列属性映射 @Column(nullable=false)
HQL 面向对象的查询语言 FROM User u WHERE u.age > 18
Criteria API 类型安全的动态查询 cb.like(root.get("name"), "%张%")


复杂场景解决方案

批量数据处理

方法 适用场景 性能特征 示例代码
AddBatch 单次插入少量数据(<500) 较快 pstmt.addBatch();
RewriteBatchedStatement 大批量插入(>1万条) 极快(减少网络IO) ((com.mysql.jdbc.StatementImpl)pstmt).enableBatchToHack();
Stream API Java 8+函数式处理 低内存占用 resultSet.stream().forEach(row -> process(row));

分布式事务处理

方案 优点 缺点 适用场景
XA两阶段提交 强一致性 性能差,锁时间长 金融交易等强一致场景
TCC事务 最终一致性,性能好 需实现Try/Confirm/Cancel接口 电商订单系统
Saga模式 异步解耦,高可用 补偿机制复杂 跨服务业务流程


常见错误排查指南

错误现象 可能原因 解决方案
Communications link failure 网络中断/数据库重启 检查网络连通性,重试机制
Access denied for user ‘root’@’host’ 权限不足/密码错误 授予相应权限,核对凭证
The column index is out of range 结果集元数据不匹配 检查SELECT字段与Java类型的映射
Too many connections 未使用连接池/最大连接数超限 启用连接池,调整maxActive参数
Data truncation 数据类型转换错误 检查字段长度/精度匹配


相关问答FAQs

Q1: 如何防止SQL载入攻破?

A: 最有效的方法是始终使用PreparedStatement代替Statement,并通过问号占位符(?)传递参数。

// 安全做法 String sql = "SELECT FROM users WHERE email = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, userInputEmail); // 自动转义特殊字符 // 危险做法(易受载入) Statement stmt = conn.createStatement(); String badSql = "SELECT FROM users WHERE email = '" + userInputEmail + "'"; // 若输入含' OR '1'='1则会被执行

补充措施:①对输入进行白名单校验 ②启用数据库防火墙 ③定期审计慢查询日志。

Q2: 查询百万级数据时出现OOM怎么办?

A: 采用以下组合策略解决:

  1. 分页查询:SELECT FROM table LIMIT 100000, 100(注意偏移量大时效率低)
  2. 游标机制:conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT)保持游标打开
  3. 流式处理:rs.setFetchSize(Integer.MIN_VALUE)禁用全量加载到内存
  4. 投影优化:仅查询必要字段而非SELECT
  5. 异步处理:将结果写入临时文件/消息队列,后续分段处理
  6. 数据库层面优化:添加合适索引,考虑分区表设计。

0