当前位置:首页 > 学海无涯 > 正文内容

Java 链接数据库与基础增删改查操作详解

清羽天2个月前 (11-27)学海无涯26


在 Java 开发中,数据库交互是绝大多数应用的核心功能之一。无论是用户信息存储、业务数据统计还是日志记录,都需要通过 Java 程序与数据库建立连接并执行数据操作。本文将以 MySQL 数据库(最常用的关系型数据库之一)为例,从环境准备、数据库连接、基础增删改查(CRUD)操作到代码优化,一步步带大家掌握 Java 操作数据库的核心技能。

一、环境准备

在开始编码前,我们需要先完成 “工具 + 依赖” 的双重准备,确保后续操作能顺利进行。

1.1 核心工具与软件

  • JDK:推荐 JDK 8 及以上版本(本文使用 JDK 11),确保 Java 开发环境正常。

  • MySQL 数据库:推荐 MySQL 8.0 版本,需提前创建测试数据库和表(下文会提供建表语句)。

  • 开发工具:IntelliJ IDEA(或 Eclipse),用于编写和运行 Java 代码。

  • 数据库连接依赖:MySQL 官方提供的 JDBC 驱动(mysql-connector-java),用于 Java 程序与 MySQL 通信。

1.2 依赖配置(Maven 方式)

如果使用 Maven 管理项目,直接在 pom.xml 中添加 JDBC 驱动依赖(无需手动下载 JAR 包):
xml
<!-- MySQL JDBC 驱动(MySQL 8.0+ 对应此依赖) --><dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.32</version> <!-- 版本可根据 MySQL 版本调整 -->
    <scope>runtime</scope></dependency>
如果是普通 Java 项目,需手动下载 MySQL JDBC 驱动 JAR 包,并在 IDE 中添加到项目的 “库” 中。

1.3 测试数据库与表创建

打开 MySQL 客户端(如 Navicat、SQLyog 或命令行),执行以下 SQL 语句,创建测试用的数据库 java_db 和用户表 user
sql
-- 1. 创建数据库(若不存在)CREATE DATABASE IF NOT EXISTS java_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;-- 2. 使用数据库USE java_db;-- 3. 创建用户表(存储用户ID、姓名、年龄、邮箱)CREATE TABLE IF NOT EXISTS user (
    id INT PRIMARY KEY AUTO_INCREMENT, -- 主键,自增
    name VARCHAR(50) NOT NULL,         -- 姓名,非空
    age INT,                           -- 年龄
    email VARCHAR(100) UNIQUE          -- 邮箱,唯一) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

二、Java 链接数据库的核心:JDBC

JDBC(Java Database Connectivity)是 Java 提供的一套用于操作数据库的标准 API,它定义了 Java 程序与数据库交互的规范,而具体的实现由各数据库厂商提供(如 MySQL 的 mysql-connector-java)。

2.1 JDBC 连接数据库的 5 个核心步骤

  1. 加载 JDBC 驱动:MySQL 8.0+ 无需显式加载(驱动会自动注册),但需确保依赖已引入。

  2. 定义数据库连接 URL:格式为 jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2

    • useSSL=false:禁用 SSL(开发环境常用,生产环境需根据需求调整)。

    • serverTimezone=UTC:设置时区(MySQL 8.0+ 必须指定,否则会报时区错误)。

    • 示例(本地 MySQL):jdbc:mysql://localhost:3306/java_db?useSSL=false&serverTimezone=UTC

    • 关键参数说明:

  3. 创建数据库连接:通过 DriverManager.getConnection(url, username, password) 获取 Connection 对象(数据库连接的核心对象)。

  4. 执行 SQL 语句:通过 Connection 创建 Statement 或 PreparedStatement 对象,执行 SQL 并处理结果。

  5. 关闭资源:依次关闭 ResultSet(结果集)、Statement(SQL 执行对象)、Connection(数据库连接),避免资源泄漏。

2.2 基础连接示例(含工具类封装)

直接在业务代码中写连接逻辑会导致冗余,因此我们先封装一个 JDBC 工具类,统一处理连接的创建和关闭:
java
import java.sql.*;/**
 * JDBC 工具类:封装数据库连接与资源关闭
 */public class JDBCUtils {
    // 数据库连接参数(建议放在配置文件中,此处为演示简化)
    private static final String URL = "jdbc:mysql://localhost:3306/java_db?useSSL=false&serverTimezone=UTC";
    private static final String USERNAME = "root"; // 你的 MySQL 用户名
    private static final String PASSWORD = "123456"; // 你的 MySQL 密码

    /**
     * 获取数据库连接
     * @return Connection 对象(若连接失败,抛出 SQLException)
     */
    public static Connection getConnection() throws SQLException {
        Connection conn = null;
        try {
            // MySQL 8.0+ 无需显式加载驱动(Driver 类会自动注册)
            // Class.forName("com.mysql.cj.jdbc.Driver"); // 旧版本需添加此句
            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            System.out.println("数据库连接成功!");
        } catch (SQLException e) {
            System.out.println("数据库连接失败!");
            throw e; // 抛出异常,由调用者处理
        }
        return conn;
    }

    /**
     * 关闭资源(ResultSet + Statement + Connection)
     * @param rs 结果集(可null)
     * @param stmt SQL执行对象(可null)
     * @param conn 数据库连接(可null)
     */
    public static void closeResources(ResultSet rs, Statement stmt, Connection conn) {
        // 关闭顺序:先ResultSet,再Statement,最后Connection(避免资源泄漏)
        try {
            if (rs != null) rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (stmt != null) stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null && !conn.isClosed()) conn.close();
            System.out.println("数据库连接已关闭!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }}
注意:实际开发中,URLUSERNAMEPASSWORD 应放在配置文件(如 jdbc.properties)中,而非硬编码,方便后期维护。

三、基础增删改查(CRUD)操作实现

有了 JDBC 工具类后,我们就可以基于它实现用户表 user 的增删改查操作。本文使用 PreparedStatement(而非 Statement),因为它能防止 SQL 注入,且性能更优(支持 SQL 预编译)。

3.1 1. 新增操作(Create)

功能:向 user 表插入一条新用户数据。
java
import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;public class JDBCCreateDemo {
    public static void main(String[] args) {
        // 1. 声明需要关闭的资源(Connection、PreparedStatement)
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            // 2. 获取数据库连接
            conn = JDBCUtils.getConnection();

            // 3. 定义SQL(? 为占位符,避免SQL注入)
            String sql = "INSERT INTO user (name, age, email) VALUES (?, ?, ?)";

            // 4. 创建PreparedStatement对象(预编译SQL)
            pstmt = conn.prepareStatement(sql);

            // 5. 为占位符赋值(参数索引从1开始)
            pstmt.setString(1, "张三");  // 第一个?:name
            pstmt.setInt(2, 25);        // 第二个?:age
            pstmt.setString(3, "zhangsan@example.com"); // 第三个?:email

            // 6. 执行SQL(新增/修改/删除用executeUpdate(),返回受影响的行数)
            int affectedRows = pstmt.executeUpdate();
            System.out.println("新增成功,受影响行数:" + affectedRows);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7. 关闭资源(调用工具类方法)
            JDBCUtils.closeResources(null, pstmt, conn);
        }
    }}

3.2 2. 查询操作(Read)

功能:根据用户 ID 查询用户信息,或查询所有用户信息。

3.2.1 按 ID 查询单个用户

java
import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class JDBCReadOneDemo {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null; // 查询操作需要ResultSet存储结果

        try {
            conn = JDBCUtils.getConnection();

            // 定义SQL:根据id查询用户
            String sql = "SELECT id, name, age, email FROM user WHERE id = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, 1); // 查询id=1的用户

            // 执行查询(用executeQuery(),返回ResultSet)
            rs = pstmt.executeQuery();

            // 处理结果集(rs.next()判断是否有下一条数据)
            if (rs.next()) {
                // 通过列名或列索引获取数据(推荐列名,避免索引变动导致错误)
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                String email = rs.getString("email");

                // 输出用户信息
                System.out.println("查询到的用户:");
                System.out.println("ID:" + id + ",姓名:" + name + ",年龄:" + age + ",邮箱:" + email);
            } else {
                System.out.println("未查询到该用户!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源(需传入ResultSet)
            JDBCUtils.closeResources(rs, pstmt, conn);
        }
    }}

3.2.2 查询所有用户

只需修改 SQL 语句和结果集处理逻辑即可:
java
// 替换SQL语句String sql = "SELECT id, name, age, email FROM user";// 处理结果集(循环获取所有数据)while (rs.next()) {
    int id = rs.getInt("id");
    String name = rs.getString("name");
    int age = rs.getInt("age");
    String email = rs.getString("email");
    System.out.println("ID:" + id + ",姓名:" + name + ",年龄:" + age + ",邮箱:" + email);}

3.3 3. 修改操作(Update)

功能:根据用户 ID 修改用户的年龄或邮箱。
java
import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;public class JDBCUpdateDemo {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = JDBCUtils.getConnection();

            // 定义SQL:修改id=1的用户年龄和邮箱
            String sql = "UPDATE user SET age = ?, email = ? WHERE id = ?";
            pstmt = conn.prepareStatement(sql);

            // 为占位符赋值
            pstmt.setInt(1, 26); // 新年龄
            pstmt.setString(2, "zhangsan_new@example.com"); // 新邮箱
            pstmt.setInt(3, 1); // 目标用户ID

            // 执行修改(executeUpdate()返回受影响行数)
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                System.out.println("修改成功!");
            } else {
                System.out.println("修改失败,未找到该用户!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResources(null, pstmt, conn);
        }
    }}

3.4 4. 删除操作(Delete)

功能:根据用户 ID 删除用户数据。
java
import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;public class JDBCDeleteDemo {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = JDBCUtils.getConnection();

            // 定义SQL:删除id=1的用户
            String sql = "DELETE FROM user WHERE id = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, 1);

            // 执行删除
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                System.out.println("删除成功!");
            } else {
                System.out.println("删除失败,未找到该用户!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResources(null, pstmt, conn);
        }
    }}

四、常见问题与优化建议

4.1 常见问题排查

  1. “时区错误”:MySQL 8.0+ 必须在 URL 中添加 serverTimezone=UTC(或 Asia/Shanghai)。

  2. “连接被拒绝”:检查 MySQL 是否启动、主机地址 / 端口号是否正确、用户是否有权限访问数据库。

  3. “SQL 注入风险”:严禁使用 Statement,必须用 PreparedStatement 并通过占位符赋值。

  4. “资源泄漏”:确保在 finally 中关闭所有资源(即使发生异常),或使用 Java 7+ 的 try-with-resources 语法自动关闭资源。

4.2 代码优化建议

  1. 使用配置文件存储连接参数:将 URLUSERNAMEPASSWORD 放在 jdbc.properties 中,通过 Properties 类读取,避免硬编码。
    properties
    # jdbc.propertiesjdbc.url=jdbc:mysql://localhost:3306/java_db?useSSL=false&serverTimezone=UTCjdbc.username=rootjdbc.password=123456
    读取方式:
    java
    public static Connection getConnection() throws SQLException, IOException {
        Properties props = new Properties();
        // 读取配置文件(放在src/main/resources目录下)
        props.load(JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
        String url = props.getProperty("jdbc.url");
        String username = props.getProperty("jdbc.username");
        String password = props.getProperty("jdbc.password");
        return DriverManager.getConnection(url, username, password);}
  2. 使用 try-with-resources 自动关闭资源:Java 7+ 提供的语法,无需手动在 finally 中关闭资源(资源需实现 AutoCloseable 接口,JDBC 相关类均已实现)。
    java
    // 示例:查询操作(自动关闭conn、pstmt、rs)try (Connection conn = JDBCUtils.getConnection();
         PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM user WHERE id = ?");
         ResultSet rs = pstmt.executeQuery()) {
         // 业务逻辑...} catch (SQLException e) {
        e.printStackTrace();}
  3. 使用数据库连接池:频繁创建 / 关闭 Connection 会消耗大量资源,实际开发中需使用连接池(如 HikariCP、C3P0),复用连接对象,提升性能。

五、总结

本文从环境准备到代码实现,详细讲解了 Java 基于 JDBC 操作 MySQL 数据库的核心流程:
  1. 掌握 JDBC 连接数据库的 5 个步骤,理解 ConnectionPreparedStatementResultSet 的作用。

  2. 实现基础增删改查操作,重点关注 PreparedStatement 的占位符用法(防 SQL 注入)。

  3. 学会封装工具类、处理资源关闭,避免冗余代码和资源泄漏。

JDBC 是 Java 操作数据库的基础,后续学习的 MyBatis、Spring Data JPA 等框架,本质上都是对 JDBC 的封装。掌握本文内容后,再学习框架会更加轻松。建议大家多动手实践,尝试修改 SQL 语句、处理异常场景,加深对 JDBC 的理解。


分享给朋友:

“Java 链接数据库与基础增删改查操作详解” 的相关文章

Linux常用命令大全

Linux常用命令大全

Linux是开发与运维工作中不可或缺的工具,掌握常用命令能显著提升效率。本篇整理了一些高频使用的命令,覆盖文件操作、系统监控、网络调试等核心场景,适合入门学习或作为日常参考使用。以下是一些常用的Linux命令:1. ls:列出当前目录中的文件和子目录ls2. pwd:显示当前工作目录的路径pwd3....

Java 自定义鼠标样式完全指南:从基础到进阶实践

在 Java 图形界面(GUI)开发中,默认鼠标样式往往难以满足个性化界面设计需求。无论是打造炫酷的游戏界面、专业的桌面应用,还是贴合品牌风格的工具软件,自定义鼠标样式都能显著提升用户体验。本文将从基础原理出发,结合 Swing 与 AWT 技术,通过实例详解 Java 自定义鼠标样式的实现方法,覆...

PHP 自定义鼠标样式完全指南:Web 场景实战(CSS 核心 + PHP 动态适配)

在 PHP 开发的 Web 应用中,自定义鼠标样式是提升界面个性化与用户体验的有效手段 —— 无论是电商平台的商品预览、创意官网的交互设计,还是后台管理系统的功能区分,合适的鼠标样式都能让操作逻辑更清晰、视觉效果更出彩。与 Java/Python 的桌面端 GUI 不同,PHP 作为服务器端语言,无...

Java 实现在线视频播放完整方案:从后端服务到前端播放

在 Web 开发中,在线视频播放是常见需求(如教育平台、视频网站、企业培训系统等)。Java 作为成熟的后端技术,能提供稳定的视频资源管理、权限控制、流式传输能力;配合前端播放器组件,可实现流畅的跨浏览器视频播放体验。本文将从技术选型、后端实现、前端集成、功能优化四个维度,手把手教你完成 Java...

PHP 链接数据库与基础增删改查(CRUD)操作详解

在 Web 开发中,PHP 与数据库的交互是动态网站的核心能力 —— 无论是用户登录注册、数据展示还是业务逻辑处理,都离不开 PHP 对数据库的增删改查操作。本文将以 MySQL 数据库(PHP 生态最常用的关系型数据库)为例,从环境准备、数据库连接、核心 CRUD 实现到安全优化,一步步...