杰瑞科技汇

Java如何操作MySQL数据库?

概览

Java 操作数据库主要遵循一个标准规范,叫做 JDBC (Java Database Connectivity),你可以把 JDBC 理解为一套“规则”或“接口”,而各个数据库厂商(如 Oracle, MySQL, SQL Server)会提供这套接口的“实现”,也就是 驱动程序

Java如何操作MySQL数据库?-图1
(图片来源网络,侵删)

整个流程可以概括为:

  1. 加载驱动:让 JVM 加载 MySQL 提供的 JDBC 驱动。
  2. 建立连接:通过 JDBC URL、用户名和密码,与 MySQL 数据库建立一个网络连接。
  3. 创建语句对象:通过连接对象,创建一个用于执行 SQL 语句的对象。
  4. 执行 SQL:使用语句对象执行 SQL(查询、更新、删除等)。
  5. 处理结果集:如果是查询操作,会返回一个结果集,你需要遍历并处理这个结果集。
  6. 关闭资源:按照“后开先关”的原则,关闭所有打开的资源(结果集、语句、连接)。

第一步:环境准备

安装 MySQL 数据库

确保你的电脑上已经安装并运行了 MySQL 数据库,如果没有,请从 MySQL 官网 下载并安装。

创建测试数据库和表

登录到你的 MySQL 客户端(如 MySQL Workbench, Navicat, 或命令行 mysql -u root -p),执行以下 SQL 语句来创建一个用于测试的数据库和表。

-- 创建一个名为 `java_test` 的数据库
CREATE DATABASE IF NOT EXISTS java_test;
-- 使用这个数据库
USE java_test;
-- 创建一个 `users` 表
CREATE TABLE IF NOT EXISTS users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入一些测试数据
INSERT INTO users (username, password, email) VALUES 
('zhangsan', '123456', 'zhangsan@example.com'),
('lisi', '654321', 'lisi@example.com');

添加 MySQL JDBC 驱动依赖

这是最关键的一步,你的 Java 项目需要知道如何与 MySQL 通信,这就需要 MySQL 的 JDBC 驱动。

使用 Maven (推荐)

如果你使用 Maven 来管理项目,在你的 pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- MySQL Connector/J 驱动 -->
    <!-- 版本号可能会更新,建议去 Maven Central 查找最新版本 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version> <!-- 使用一个较新的稳定版本 -->
    </dependency>
</dependencies>

手动下载 JAR 包

  1. Maven Central Repository 查找 mysql-connector-j
  2. 下载对应版本的 JAR 文件(mysql-connector-j-8.0.33.jar)。
  3. 将下载的 JAR 文件添加到你的项目的类路径中,在 IDE(如 IntelliJ IDEA 或 Eclipse)中,通常右键项目 -> Build Path / Project Structure -> Libraries -> Add External JARs...

第二步:编写 Java 代码

下面我们通过几个完整的示例来演示 Java 如何操作 MySQL。

示例 1:查询数据 (SELECT)

这个示例会连接数据库,查询 users 表中的所有数据,并打印出来。

import java.sql.*;
public class SelectExample {
    // 数据库连接信息
    // 注意:如果你的 MySQL 版本 >= 8.0,通常需要指定时区 serverTimezone=UTC
    private static final String URL = "jdbc:mysql://localhost:3306/java_test?serverTimezone=UTC";
    private static final String USER = "root"; // 你的 MySQL 用户名
    private static final String PASSWORD = "your_password"; // 你的 MySQL 密码
    public static void main(String[] args) {
        // 使用 try-with-resources 语句,可以自动关闭资源,非常推荐!
        // Connection, Statement, ResultSet 都实现了 AutoCloseable 接口
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT id, username, email FROM users")) {
            // 检查是否有数据
            if (!rs.isBeforeFirst()) {
                System.out.println("表中没有数据。");
                return;
            }
            System.out.println("用户列表:");
            System.out.println("---------------------------------");
            // 遍历结果集
            while (rs.next()) {
                // 通过列名获取数据,更具可读性,且不易因列顺序改变而出错
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String email = rs.getString("email");
                // 打印数据
                System.out.printf("ID: %d, 用户名: %s, 邮箱: %s%n", id, username, email);
            }
        } catch (SQLException e) {
            System.err.println("数据库查询出错!");
            e.printStackTrace();
        }
    }
}

代码解释:

  • DriverManager.getConnection(): 尝试建立与数据库的连接。
  • conn.createStatement(): 创建一个 Statement 对象,用于执行静态 SQL 语句。
  • stmt.executeQuery(): 执行查询,返回一个 ResultSet 对象,结果集包含了查询返回的数据。
  • rs.next(): 将光标从当前位置向下移动一行,如果新的一行有效,则返回 true,否则返回 false
  • rs.getInt("id"), rs.getString("username"): 根据列名获取当前行的数据,并转换为对应的 Java 类型。
  • try-with-resources: 这是 Java 7 引入的一个语法糖,它会自动在 try 代码块执行完毕后关闭括号内声明的资源,避免了手动关闭时可能出现的资源泄漏问题。

示例 2:插入数据 (INSERT)

import java.sql.*;
public class InsertExample {
    private static final String URL = "jdbc:mysql://localhost:3306/java_test?serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "your_password";
    public static void main(String[] args) {
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        // 使用 try-with-resources 确保 Connection, PreparedStatement 被关闭
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
             // 使用 PreparedStatement 可以防止 SQL 注入,并且能预编译 SQL,提高性能
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数 (索引从 1 开始)
            pstmt.setString(1, "wangwu");
            pstmt.setString(2, "wangwu123");
            pstmt.setString(3, "wangwu@example.com");
            // 执行更新操作,返回受影响的行数
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                System.out.println("成功插入新用户!");
            } else {
                System.out.println("插入失败。");
            }
        } catch (SQLException e) {
            System.err.println("数据库插入出错!");
            e.printStackTrace();
        }
    }
}

代码解释:

  • PreparedStatement: 这是 Statement 的一个子接口,用于执行预编译的 SQL 语句。
  • 优点
    1. 防止 SQL 注入:通过使用 作为占位符,并将用户输入作为参数传入,可以避免恶意 SQL 代码的执行。
    2. 性能更高:如果同一个 SQL 被多次执行(只是参数不同),数据库可以预编译它,后续执行只需传入参数即可,速度更快。
  • pstmt.setString(1, "wangwu"): 将第一个 占位符替换为字符串 "wangwu",索引从 1 开始。
  • pstmt.executeUpdate(): 执行 INSERT, UPDATE, DELETE 等更新操作,返回一个整数,表示受影响的行数。

示例 3:更新数据 (UPDATE) 和删除数据 (DELETE)

这两个操作与 INSERT 非常相似,都使用 PreparedStatement.executeUpdate()

更新数据示例:

String sql = "UPDATE users SET email = ? WHERE username = ?";
try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setString(1, "new_lisi@example.com");
    pstmt.setString(2, "lisi");
    int affectedRows = pstmt.executeUpdate();
    System.out.println(affectedRows + " 行数据被更新。");
} catch (SQLException e) {
    e.printStackTrace();
}

删除数据示例:

String sql = "DELETE FROM users WHERE username = ?";
try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setString(1, "zhangsan");
    int affectedRows = pstmt.executeUpdate();
    System.out.println(affectedRows + " 行数据被删除。");
} catch (SQLException e) {
    e.printStackTrace();
}

最佳实践和高级主题

使用连接池

在真实的应用中,频繁地创建和销毁数据库连接是非常消耗性能的。连接池 应运而生。

连接池会在初始化时创建一组数据库连接,并将它们缓存起来,当需要连接时,从池中获取一个用完后再放回池中,而不是关闭,这极大地提高了性能。

常用连接池库:

  • HikariCP: 目前性能最好的连接池,是 Spring Boot 2.x 的默认选择。
  • Apache DBCP
  • C3P0

使用 HikariCP 的示例:

pom.xml 中添加 HikariCP 依赖:

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

然后修改代码:

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class HikariCPExample {
    public static void main(String[] args) {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/java_test?serverTimezone=UTC");
        config.setUsername("root");
        config.setPassword("your_password");
        // 连接池配置
        config.setMaximumPoolSize(10); // 最大连接数
        config.setMinimumIdle(5);     // 最小空闲连接数
        config.setConnectionTimeout(30000); // 连接超时时间 (ms)
        // 创建数据源 (连接池)
        try (HikariDataSource dataSource = new HikariDataSource(config);
             Connection conn = dataSource.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT username FROM users")) {
            System.out.println("从连接池获取连接成功!");
            while (rs.next()) {
                System.out.println("用户名: " + rs.getString("username"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意:在实际项目中,数据源(连接池)通常是全局唯一的,应该作为单例来管理。

使用 JPA / MyBatis 等 ORM 框架

对于复杂的项目,直接写 JDBC 代码会变得非常繁琐(需要手动映射结果集到 Java 对象),这时会使用 ORM (Object-Relational Mapping) 框架。

  • JPA (Java Persistence API): Java 官方的 ORM 规范,通过注解或 XML 描述对象和数据库表的映射关系,Hibernate 是其最流行的实现。
  • MyBatis: 一个优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射,相比全自动的 ORM,MyBatis 更加灵活,可以让你更好地控制 SQL。

这些框架能帮你把数据库操作从繁琐的 JDBC 代码中解放出来,让你更专注于业务逻辑。

操作 核心类/方法 说明
加载驱动 Class.forName("com.mysql.cj.jdbc.Driver") JDBC 4.0+ 后通常不需要手动加载
建立连接 DriverManager.getConnection(url, user, password) 获取 Connection 对象
创建语句 conn.createStatement()conn.prepareStatement(sql) 获取 StatementPreparedStatement
执行查询 stmt.executeQuery(sql) 返回 ResultSet
执行更新 stmt.executeUpdate(sql) 返回受影响的行数
处理结果 rs.next(), rs.getXxx() 遍历和获取结果集数据
关闭资源 rs.close(), stmt.close(), conn.close() 或使用 try-with-resources 自动关闭

对于初学者,掌握 PreparedStatementtry-with-resources 是最重要的两个好习惯,对于实际项目,强烈建议使用 连接池ORM 框架

分享:
扫描分享到社交APP
上一篇
下一篇