上一篇
java中怎么使用数据库
- 数据库
- 2025-08-14
- 1
在Java中使用数据库需引入JDBC驱动,加载驱动类,建立连接,创建Statement对象,执行SQL语句,处理ResultSet结果集,最后
核心前置条件
1 技术栈组成
组件 | 作用 | 典型实现 |
---|---|---|
JDBC API | Java标准接口,统一访问关系型数据库 | java.sql 包 |
驱动管理器 | 动态加载数据库厂商提供的JDBC驱动 | Class.forName() |
数据库驱动 | 实现JDBC接口的具体类(不同数据库需对应驱动) | MySQL Connector/J |
物理连接 | 通过网络协议与数据库服务器建立TCP长连接 | DriverManager.getConnection() |
SQL引擎 | 解析并执行SQL语句,返回结果集 | Database Server内部模块 |
2 环境准备清单
开发工具: IntelliJ IDEA/Eclipse + Maven/Gradle
依赖配置 (以MySQL为例):
<!-pom.xml --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> <!-根据实际版本调整 --> </dependency>
️ 注意: 不同数据库驱动包名称不同(Oracle为ojdbcX.jar,PostgreSQL为postgresql-XX.jar)
标准开发流程详解
1 七步标准操作法
序号 | 步骤 | 关键代码示例 | 说明 |
---|---|---|---|
1 | 加载数据库驱动 | Class.forName("com.mysql.cj.jdbc.Driver") |
触发静态初始化块注册驱动到DriverManager |
2 | 建立数据库连接 | DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "password") |
URL格式:协议://主机:端口/数据库名 |
3 | 创建执行器对象 | Connection con = ...;<br>Statement stmt = con.createStatement(); |
三种执行器类型:Statement/PreparedStatement/CallableStatement |
4 | 执行SQL语句 | ResultSet rs = stmt.executeQuery("SELECT FROM users"); |
executeQuery()用于查询,executeUpdate()用于DML/DDL |
5 | 处理结果集 | while(rs.next()){ System.out.println(rs.getString("username")); } |
通过游标逐行读取,列索引从1开始/列名直接获取 |
6 | 事务控制 | con.setAutoCommit(false);<br>// 多条SQL后<br>con.commit(); |
默认自动提交,显式事务需关闭自动提交+手动提交/回滚 |
7 | 资源释放 | rs.close();<br>stmt.close();<br>con.close(); |
逆向顺序关闭,建议使用try-with-resources自动管理 |
2 完整代码演示(带注释)
import java.sql.; public class JdbcDemo { public static void main(String[] args) { Connection connection = null; PreparedStatement pstmt = null; ResultSet resultSet = null; try { // 1. 加载驱动(新版MySQL可省略此步) Class.forName("com.mysql.cj.jdbc.Driver"); // 2. 建立连接(URL含时区配置) String url = "jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC"; connection = DriverManager.getConnection(url, "root", "123456"); // 3. 使用预编译语句防止SQL注入 String sql = "SELECT id, name, email FROM users WHERE age > ?"; pstmt = connection.prepareStatement(sql); pstmt.setInt(1, 18); // 设置第一个占位符的值 // 4. 执行查询 resultSet = pstmt.executeQuery(); // 5. 处理结果集 while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); String email = resultSet.getString("email"); System.out.printf("ID:%d Name:%s Email:%s%n", id, name, email); } // 6. 执行更新操作示例 int affectedRows = pstmt.executeUpdate("UPDATE users SET status=1 WHERE id=100"); System.out.println("更新了" + affectedRows + "条记录"); } catch (ClassNotFoundException e) { System.err.println("驱动加载失败:" + e.getMessage()); } catch (SQLException e) { System.err.println("数据库操作异常:" + e.getMessage()); try { if (connection != null) connection.rollback(); // 事务回滚 } catch (SQLException ex) { ex.printStackTrace(); } } finally { // 7. 资源释放(按相反顺序) try { if(resultSet != null) resultSet.close(); } catch(SQLException e){} try { if(pstmt != null) pstmt.close(); } catch(SQLException e){} try { if(connection != null) connection.close(); } catch(SQLException e){} } } }
关键要素深度解析
1 三种执行器对比表
特性 | Statement | PreparedStatement | CallableStatement |
---|---|---|---|
主要用途 | 简单SQL执行 | 带参数的预编译SQL | 存储过程调用 |
SQL注入防护 | 不安全 | 参数化查询 | |
执行效率 | 较低(每次编译) | 高(首次编译后缓存) | 高 |
批处理支持 | 有限 | batchUpdate() | |
适用场景 | 一次性简单查询 | 重复执行的参数化查询 | T-SQL/PL/SQL脚本执行 |
2 连接池优化方案
方案 | 特点 | 推荐场景 |
---|---|---|
HikariCP | 轻量级高性能,默认最大10个连接 | Web应用首选 |
Druid | 监控统计功能强大,支持SQL防火墙 | 企业级应用 |
DBCP | Tomcat自带,配置简单 | 小型项目快速集成 |
C3P0 | 历史悠久,功能全面 | 传统项目维护 |
示例配置(HikariCP):
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> </dependency>
HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb"); config.setUsername("root"); config.setPassword("123456"); config.setMaximumPoolSize(10); // 最大连接数 HikariDataSource ds = new HikariDataSource(config); Connection connection = ds.getConnection();
高级技巧与注意事项
1 SQL注入防御策略
错误写法:字符串拼接会导致破绽
String sql = "SELECT FROM users WHERE username='" + userInput + "'"; // 危险!
️ 正确做法:强制使用预编译语句
String sql = "SELECT FROM users WHERE username=?"; PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, userInput); // 自动转义特殊字符
2 批量操作优化
String sql = "INSERT INTO logs(content) VALUES(?)"; connection.setAutoCommit(false); // 关闭自动提交提升性能 PreparedStatement pstmt = connection.prepareStatement(sql); for (String log : logList) { pstmt.setString(1, log); pstmt.addBatch(); // 加入批处理队列 } int[] results = pstmt.executeBatch(); // 批量执行 connection.commit(); // 手动提交事务
3 BLOB/CLOB大字段处理
// 读取图片文件 Blob imageBlob = resultSet.getBlob("avatar"); InputStream binaryStream = imageBlob.getBinaryStream(); byte[] bytes = binaryStream.readAllBytes(); // Java 9+方法 // 写入文本文档 Clob documentClob = connection.createClob(); documentClob.setString(1, "大量文本内容"); pstmt.setClob(1, documentClob);
常见错误及解决方案
错误类型 | 典型表现 | 根本原因 | 解决方案 |
---|---|---|---|
CommunicationsException | java.sql.SQLException: No suitable driver found | 未加载驱动或驱动不匹配 | 检查Class.forName()和驱动版本 |
Access denied | SQLSTATE[HY000] [28000] | 数据库权限不足 | 授予用户相应表的操作权限 |
Latin-1 encoding error | 中文乱码 | 字符集配置不一致 | URL添加?characterEncoding=UTF-8 |
Too many connections | Exceeded maximum pool size | 连接未及时释放 | 使用连接池+合理设置超时时间 |
Lock wait timeout | Deadlock found when trying to get lock | 事务竞争导致死锁 | 缩小事务范围+重试机制 |
相关问答FAQs
Q1: 为什么会出现”No suitable driver found”错误?
A: 此错误通常由以下原因导致:①未正确加载数据库驱动(忘记调用Class.forName());②使用的驱动版本与数据库版本不兼容;③Maven依赖未正确导入,解决方案:检查pom.xml中的驱动依赖版本,确认已添加对应的Class.forName()调用,且驱动JAR包确实存在于classpath中。
Q2: 如何处理数据库连接时的中文乱码问题?
A: 中文乱码的根本原因是字符集编码不一致,解决方法:①在数据库连接URL中添加参数?characterEncoding=UTF-8&useUnicode=true
;②确保数据库表的字符集设置为utf8mb4;③在Java代码中统一使用UTF-8编码,例如连接字符串应为:jdbc:mysql://localhost:3306/mydb?characterEncoding=UTF-8&useUnicode=true&serverTimezone=UTC