自学教程

MySQL Java JDBC 连接与使用

JDBC(Java Database Connectivity)是 Java 官方定义的数据库访问标准接口,通过它可以在 Java 程序中连接 MySQL,执行 SQL、处理结果集。

说明:旧驱动 com.mysql.jdbc.Driver 已废弃。MySQL 8+ 使用驱动类 com.mysql.cj.jdbc.Driver,驱动包为 mysql-connector-j(原 mysql-connector-java)。

本教程使用到的 Websites 表 SQL 文件:websites.sql。

一、环境准备

1. 引入驱动包

Maven(pom.xml)

<!-- MySQL 8.x 驱动,推荐 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.4.0</version>
</dependency>

Gradle

implementation 'com.mysql:mysql-connector-j:8.4.0'

2. 准备测试数据表

沿用前面教程的 websites 表,方便统一测试:

CREATE DATABASE IF NOT EXISTS test;
USE test;
DROP TABLE IF EXISTS websites;
CREATE TABLE websites (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(20),
  url VARCHAR(255),
  alexa INT,
  country VARCHAR(10)
);INSERT INTO websites(name,url,alexa,country) VALUES
('Google','https://www.google.com',1,'USA'),
('淘宝','https://www.taobao.com',13,'CN'),
('runoops教程','http://runoops.com',6988,'CN'),
('微博','http://weibo.com',22,'CN'),
('Facebook','https://www.facebook.com',3,'USA');

二、基础连接(原生JDBC,不推荐生产)

原生写法:手动获取连接、Statement、结果集,务必关闭资源;生产环境不要直接用,优先使用连接池 HikariCP。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class JdbcConnectDemo {
public static void main(String[] args) {
// 连接URL
String url = "jdbc:mysql://localhost:3306/test"
+ "?useSSL=false"
+ "&serverTimezone=Asia/Shanghai"
+ "&characterEncoding=utf8mb4";
String user = "root";
String password = "你的数据库密码"; Connection conn = null; try { // MySQL8.0+ 可省略 Class.forName,驱动自动注册 // Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection(url, user, password); System.out.println("数据库连接成功"); } catch (SQLException e) { e.printStackTrace(); } finally { // 关闭连接 if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
}

URL 参数说明:

  • serverTimezone=Asia/Shanghai:必须配置,解决时区报错
  • characterEncoding=utf8mb4:完整支持中文、Emoji
  • useSSL=false:本地开发关闭SSL;生产环境建议开启

三、CRUD 增删改查(推荐 PreparedStatement 预处理,防SQL注入)

✅ 禁止使用 Statement 拼接SQL,极易产生SQL注入;一律使用 PreparedStatement 占位符 ?。

3.1 查询 SELECT

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class JdbcSelect {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4";
String user = "root";
String pwd = "你的数据库密码"; String sql = "SELECT id,name,url,alexa,country FROM websites WHERE alexa < ?"; try (Connection conn = DriverManager.getConnection(url, user, pwd); PreparedStatement pstmt = conn.prepareStatement(sql)) { // 设置占位符参数,下标从1开始 pstmt.setInt(1, 50); ResultSet rs = pstmt.executeQuery(); // 遍历结果集 while (rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); String urlVal = rs.getString("url"); int alexa = rs.getInt("alexa"); String country = rs.getString("country"); System.out.printf("id:%d, name:%s, url:%s, alexa:%d, country:%s%n", id, name, urlVal, alexa, country); } rs.close(); } catch (SQLException e) { e.printStackTrace(); } }
}

3.2 插入 INSERT

public class JdbcInsert {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4";
        String user = "root";
        String pwd = "你的数据库密码";
        String sql = "INSERT INTO websites(name,url,alexa,country) VALUES (?,?,?,?)";    try (Connection conn = DriverManager.getConnection(url, user, pwd);
         PreparedStatement pstmt = conn.prepareStatement(sql)) {

        pstmt.setString(1, "Java教程");
        pstmt.setString(2, "[https://demo.java.com](https://demo.java.com)");
        pstmt.setInt(3, 12345);
        pstmt.setString(4, "CN");

        int affectedRows = pstmt.executeUpdate();
        System.out.println("新增影响行数:" + affectedRows);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
}

3.3 更新 UPDATE

String sql = "UPDATE websites SET name = ?, url = ? WHERE id = ?";
try (Connection conn = DriverManager.getConnection(url, user, pwd);
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setString(1, "新网站名称");
    pstmt.setString(2, "[https://new-demo.com](https://new-demo.com)");
    pstmt.setInt(3, 6);
    int affectedRows = pstmt.executeUpdate();
    System.out.println("更新行数:" + affectedRows);
} catch (SQLException e) {
    e.printStackTrace();
}

3.4 删除 DELETE

String sql = "DELETE FROM websites WHERE id = ?";
try (Connection conn = DriverManager.getConnection(url, user, pwd);
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setInt(1, 6);
    int affectedRows = pstmt.executeUpdate();
    System.out.println("删除行数:" + affectedRows);
} catch (SQLException e) {
    e.printStackTrace();
}

注意:executeQuery() 用于查询(返回ResultSet);executeUpdate() 用于 INSERT / UPDATE / DELETE,返回受影响行数。

四、事务处理

JDBC 默认自动提交(每一条SQL自动commit);事务场景需要手动关闭自动提交,成功则commit,异常rollback。

try (Connection conn = DriverManager.getConnection(url, user, pwd)) {
    // 关闭自动提交,开启事务
    conn.setAutoCommit(false);String sql1 = "UPDATE xxx SET ... WHERE id=?";
String sql2 = "UPDATE xxx SET ... WHERE id=?";
try (PreparedStatement p1 = conn.prepareStatement(sql1);
     PreparedStatement p2 = conn.prepareStatement(sql2)) {
    // 设置参数、执行SQL
    p1.executeUpdate();
    p2.executeUpdate();

    // 全部成功,提交事务
    conn.commit();
    System.out.println("事务提交成功");
} catch (SQLException e) {
    // 异常回滚
    conn.rollback();
    System.err.println("事务回滚");
    throw e;
}
} catch (SQLException e) {
e.printStackTrace();
}

五、生产推荐:HikariCP 连接池

DriverManager 每次新建连接性能极差,Java 项目标准方案:HikariCP(SpringBoot默认连接池)。

Maven 引入 HikariCP

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version>
</dependency>

HikariCP 简单示例

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;public class HikariDemo {
public static void main(String[] args) throws Exception {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4");
config.setUsername("root");
config.setPassword("你的数据库密码");
config.setMinimumIdle(5); // 最小空闲连接
config.setMaximumPoolSize(10);// 最大连接数 try (HikariDataSource ds = new HikariDataSource(config); Connection conn = ds.getConnection(); PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM websites")) { ResultSet rs = pstmt.executeQuery(); while (rs.next()) { System.out.println(rs.getString("name")); } } }
}

六、错误处理与调试

  1. 使用 try-with-resources(try() 语法),自动关闭 Connection、PreparedStatement、ResultSet,避免资源泄漏。
  2. SQLException 包含错误码 e.getErrorCode()、SQL状态码 e.getSQLState()。
    • Access denied for user:账号密码错误、授权问题
    • Unknown database:数据库名错误
    • Table doesn't exist:表不存在
    • Communications link failure:网络、防火墙、MySQL服务未启动、时区配置错误
  3. 开发环境打印完整异常栈;生产环境禁止把数据库原始异常直接返回前端,仅记录日志,返回通用提示。
  4. 调试:打印完整执行SQL、参数;在MySQL开启慢查询日志定位慢SQL。

七、性能优化与安全建议

安全

  1. 必须使用 PreparedStatement 预处理,禁止字符串拼接SQL,防止SQL注入。
  2. 数据库账号最小权限原则,业务账号不允许 DROP、ALTER。
  3. 数据库密码不要硬编码写代码,放到配置文件/环境变量,配置文件禁止提交到代码仓库。

SQL 优化

  1. 避免 SELECT *,只查询需要的字段,减少网络传输。
  2. 查询务必加 LIMIT,防止一次性读取海量数据 OOM。
  3. WHERE、ORDER BY、GROUP BY 字段建立索引;%前缀模糊查询会索引失效。
  4. 批量操作使用 addBatch() + executeBatch() 批量执行,不要循环单条执行。

连接池优化

  1. 使用 HikariCP,不要使用 DriverManager 原生连接。
  2. 合理设置 maximumPoolSize,不要过大,防止打满MySQL连接。
  3. 事务尽量简短,缩短持有连接时间,减少锁竞争、死锁。
  4. 及时释放连接;try-with-resources 自动释放资源,杜绝连接泄漏。

字符与时区

统一 utf8mb4;URL 必须配置 serverTimezone=Asia/Shanghai,避免时间异常。

八、JDBC 核心接口简要说明

接口作用
Connection数据库连接对象
PreparedStatement预编译SQL,推荐,防注入
Statement静态SQL,不推荐,存在注入风险
ResultSetSQL查询结果集
DriverManager驱动管理器(原生,生产不推荐)
标签:

0 条笔记