核心概念
Java 连接数据库主要依赖于一套标准规范,称为 JDBC (Java Database Connectivity),JDBC 本身不是一个具体的数据库驱动,而是一套 API 接口,数据库厂商(如 Oracle, MySQL, Microsoft)需要实现这套接口,提供我们称之为 JDBC 驱动 的具体类库。

连接数据库的步骤可以概括为:
- 加载驱动:告诉 JVM 使用哪个厂商的 JDBC 驱动。
- 获取连接:使用 JDBC URL、用户名和密码来建立与数据库的连接通道。
- 创建执行语句:通过连接对象创建
Statement或PreparedStatement来执行 SQL 语句。 - 处理结果集:如果是查询语句,需要获取并处理返回的结果集
ResultSet。 - 关闭资源:按相反的顺序关闭
ResultSet,Statement, 和Connection,以释放数据库资源。
第一步:准备工作(获取 JDBC 驱动)
在编写代码之前,您必须先获取对应数据库的 JDBC 驱动程序(通常是 .jar 文件),在现代 Java 开发中,推荐使用 Maven 或 Gradle 来管理依赖,这样更加方便。
以下是一些主流数据库的 Maven 依赖配置:
MySQL
<!-- 在 pom.xml 文件中添加 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version> <!-- 请使用最新的稳定版本 -->
</dependency>
SQL Server (Microsoft)
<!-- 在 pom.xml 文件中添加 -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>11.2.1.jre11</version> <!-- 请使用与您 JDK 版本匹配的最新版本 -->
</dependency>
PostgreSQL
<!-- 在 pom.xml 文件中添加 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version> <!-- 请使用最新的稳定版本 -->
</dependency>
Oracle
<!-- 在 pom.xml 文件中添加 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.3.0.0</version> <!-- 请使用最新的稳定版本 -->
</dependency>
第二步:编写 Java 连接代码
下面以最常用的 MySQL 为例,展示完整的连接、查询和关闭资源的代码。

示例 1:基础连接与查询(使用 try-with-resources)
这是推荐的方式,try-with-resources 语句会自动关闭实现了 AutoCloseable 接口的对象(如 Connection, Statement, ResultSet),无需手动 close(),能有效防止资源泄漏。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcExample {
// 数据库连接信息
// 注意:如果使用 MySQL 8+,驱动类名和 URL 稍有不同
private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC";
private static final String USER = "your_username";
private static final String PASS = "your_password";
public static void main(String[] args) {
// 1. 加载驱动 (对于现代 JDBC 驱动,这一步通常是可选的,但保留它更明确)
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.err.println("找不到 MySQL JDBC Driver!");
e.printStackTrace();
return;
}
// 使用 try-with-resources 自动管理资源
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users")) {
System.out.println("成功连接到数据库!");
// 3. 处理结果集
while (rs.next()) {
// 通过列名获取数据,更安全且可读性更好
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
// 打印数据
System.out.print("ID: " + id);
System.out.print(", 姓名: " + name);
System.out.println(", 邮箱: " + email);
}
} catch (SQLException e) {
System.err.println("数据库连接或查询出错!");
e.printStackTrace();
}
}
}
示例 2:使用 PreparedStatement (推荐用于执行 SQL)
PreparedStatement 用于执行预编译的 SQL 语句,可以有效防止 SQL 注入,并且在多次执行相同 SQL(只是参数不同)时性能更优。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcPreparedStatementExample {
private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC";
private static final String USER = "your_username";
private static final String PASS = "your_password";
public static void main(String[] args) {
String sql = "SELECT * FROM users WHERE email = ?"; // 使用 ? 作为占位符
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 设置参数,索引从 1 开始
pstmt.setString(1, "test@example.com");
// 执行查询
try (ResultSet rs = pstmt.executeQuery()) {
System.out.println("查询结果:");
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", 姓名: " + rs.getString("name"));
}
}
} catch (SQLException e) {
System.err.println("SQL 执行出错!");
e.printStackTrace();
}
}
}
示例 3:执行 INSERT, UPDATE, DELETE 语句
这些操作不返回 ResultSet,而是返回一个整数,表示受影响的行数。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JdbcUpdateExample {
private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC";
private static final String USER = "your_username";
private static final String PASS = "your_password";
public static void main(String[] args) {
// 插入新用户
String insertSql = "INSERT INTO users (name, email) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement pstmt = conn.prepareStatement(insertSql)) {
pstmt.setString(1, "张三");
pstmt.setString(2, "zhangsan@example.com");
int affectedRows = pstmt.executeUpdate();
System.out.println(affectedRows + " 行数据被插入。");
} catch (SQLException e) {
e.printStackTrace();
}
// 更新用户信息
String updateSql = "UPDATE users SET name = ? WHERE email = ?";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement pstmt = conn.prepareStatement(updateSql)) {
pstmt.setString(1, "李四");
pstmt.setString(2, "zhangsan@example.com"); // 假设要更新这个邮箱的用户
int affectedRows = pstmt.executeUpdate();
System.out.println(affectedRows + " 行数据被更新。");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
第三步:不同数据库的 URL 和驱动类
为了方便您参考,这里列出其他常见数据库的连接信息。

| 数据库 | JDBC URL 示例 | 驱动类名 (Class.forName) | 备注 |
|---|---|---|---|
| MySQL 8+ | jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC |
com.mysql.cj.jdbc.Driver |
必须指定时区 serverTimezone |
| MySQL 5.x | jdbc:mysql://localhost:3306/mydb |
com.mysql.jdbc.Driver |
旧版驱动 |
| PostgreSQL | jdbc:postgresql://localhost:5432/mydb |
org.postgresql.Driver |
|
| SQL Server | jdbc:sqlserver://localhost:1433;databaseName=mydb;encrypt=false |
com.microsoft.sqlserver.jdbc.SQLServerDriver |
encrypt=false 可用于本地开发 |
| Oracle | jdbc:oracle:thin:@localhost:1521:ORCL |
oracle.jdbc.driver.OracleDriver |
ORCL 是 SID,也可能是服务名 |
第四步:最佳实践与注意事项
- 不要硬编码连接信息:将数据库 URL、用户名、密码等配置信息放在外部文件(如
config.properties)或环境变量中,而不是直接写在代码里。 - 使用连接池:在真实的应用中,频繁地创建和销毁连接是非常消耗资源的,应该使用数据库连接池(如 HikariCP, Druid, C3P0)来管理连接,HikariCP 是目前性能最好的连接池之一。
- 始终使用
PreparedStatement:除非你 100% 确定你的 SQL 是静态的、不会被用户输入影响,否则永远不要使用Statement来拼接 SQL。PreparedStatement是防止 SQL 注入的黄金标准。 - 正确处理异常:
SQLException是检查型异常,必须处理,不要简单地printStackTrace(),应该记录日志,并根据业务需要进行重试或向用户返回友好的错误信息。 - 关闭资源:牢记
ResultSet->Statement->Connection的关闭顺序,使用try-with-resources是最简单可靠的方式。
