【Java Web】JDBC 连接 MySQL 实现数据库 CRUD(增删改查)详解

       在 Java Web 开发中,与数据库交互是不可避免的,而 JDBC(Java Database Connectivity) 是 Java 官方提供的标准数据库连接接口,几乎所有 Java 项目中都用过它。
本文通过一个完整示例,带你从零实现 增(Insert)、删(Delete)、改(Update)、查(Select) 四大功能,并配合流程图、表结构图深入分析 JDBC 的执行原理与优化方案。


一、JDBC 基本工作流程

       JDBC 是一套标准 API,任何数据库厂商只要提供 JDBC 驱动,就可以通过相同的代码访问不同数据库。它的基本执行步骤如下:

  1. 加载数据库驱动(Class.forName)

  2. 建立数据库连接(DriverManager.getConnection)

  3. 创建 Statement 对象(connection.createStatement)

  4. 执行 SQL 语句(executeQuery / executeUpdate)

  5. 处理结果集(ResultSet)

  6. 释放资源(关闭 ResultSet、Statement、Connection)


二、数据库表结构设计

我们以一个 qwe 表为例,存储学生信息。

表结构图:

+---------+-------------+----------+-------------+
| 字段名   | 数据类型    | 约束      | 描述        |
+---------+-------------+----------+-------------+
| id      | INT         | 主键自增  | 学生编号    |
| name    | VARCHAR(50) | NOT NULL | 学生姓名    |
| age     | INT         |          | 年龄        |
| sex     | VARCHAR(5)  |          | 性别        |
| classid | INT         |          | 班级ID      |
+---------+-------------+----------+-------------+

SQL 创建语句:

CREATE TABLE qwe (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    age INT,
    sex VARCHAR(5),
    classid INT
);

三、完整 JDBC 代码实现 CRUD

以下代码基于 MySQL 8.0 驱动,适用于 Java SE / Java Web 项目。

package com.qcby.db;

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

/**
 * JDBC 操作 MySQL 实现增删改查
 * 适用于 Java SE / Java Web
 */
public class Test {

    public static void main(String[] args) {
        // SQL 示例(注意:实际项目中应使用 PreparedStatement)
        String sqlSelect = "SELECT * FROM qwe";
        String sqlInsert = "INSERT INTO qwe(name, age, sex, classid) VALUES('ppp', 18, '女', 3)";
        String sqlUpdate = "UPDATE qwe SET name = '修改后的名字' WHERE id = 1";
        String sqlDelete = "DELETE FROM qwe WHERE id = 2";

        // 调用方法
        System.out.println(search(sqlSelect));
        System.out.println("插入数据条数:" + add(sqlInsert));
        System.out.println("修改数据条数:" + update(sqlUpdate));
        System.out.println("删除数据条数:" + delete(sqlDelete));
    }

    /**
     * 查询方法
     * @param sql 查询语句
     * @return JSON 格式的查询结果
     */
    public static String search(String sql) {
        try {
            // 1. 加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2. 获取连接
            String url = "jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
            String user = "root";
            String password = "123456";
            Connection connection = DriverManager.getConnection(url, user, password);

            // 3. 创建 Statement 对象
            Statement statement = connection.createStatement();

            // 4. 执行查询
            ResultSet resultSet = statement.executeQuery(sql);

            // 5. 封装结果为 JSON 格式
            StringBuilder res = new StringBuilder("[");
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String sex = resultSet.getString("sex");
                int age = resultSet.getInt("age");
                int classid = resultSet.getInt("classid");

                res.append(String.format("{\"id\":%d,\"name\":\"%s\",\"sex\":\"%s\",\"age\":%d,\"classid\":%d},",
                        id, name, sex, age, classid));
            }
            if (res.length() > 1) {
                res.setLength(res.length() - 1); // 去掉最后的逗号
            }
            res.append("]");

            // 6. 释放资源(建议在 finally 块中关闭)
            resultSet.close();
            statement.close();
            connection.close();

            return res.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    // 添加
    public static int add(String sql) {
        return executeUpdate(sql);
    }

    // 修改
    public static int update(String sql) {
        return executeUpdate(sql);
    }

    // 删除
    public static int delete(String sql) {
        return executeUpdate(sql);
    }

    /**
     * 公共执行方法(Insert、Update、Delete)
     */
    private static int executeUpdate(String sql) {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
            String user = "root";
            String password = "123456";

            Connection connection = DriverManager.getConnection(url, user, password);
            Statement statement = connection.createStatement();

            int num = statement.executeUpdate(sql);

            statement.close();
            connection.close();

            return num;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

改进建议:

  • 资源关闭:推荐用 try-with-resources 自动关闭 Connection、Statement、ResultSet,避免忘记关闭导致连接泄露。

  • 防 SQL 注入:实际开发中应使用 PreparedStatement 而不是直接拼接字符串。

💡 小 Tips:SQL 注入(SQL Injection)

定义
        SQL 注入是一种 Web 安全漏洞,攻击者通过在输入字段中插入恶意 SQL 代码,使程序在执行数据库查询时被篡改,从而绕过认证、窃取或篡改数据。

防护三步曲

1.永远不要拼接用户输入到 SQL

// ❌ 危险
"SELECT * FROM users WHERE name='" + name + "'"

 2.使用预编译(PreparedStatement)绑定参数

// ✅ 安全
String sql = "SELECT * FROM users WHERE name=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);

3.输入校验 + 最小权限 + 关闭错误回显

  • 限制输入长度与字符范围(白名单优先)

  • 数据库账号仅赋予必需权限

  • 生产环境关闭详细 SQL 错误输出


四、关键知识点详解

1. 驱动加载

Class.forName("com.mysql.cj.jdbc.Driver");
  • MySQL 8.x 驱动类com.mysql.cj.jdbc.Driver

  • 为什么手动加载? 早期 JDBC 版本需要显式加载驱动,现在有 SPI 自动加载机制,但手动加载能提高兼容性。

  • 常见报错ClassNotFoundException,说明 mysql-connector-java 依赖未导入。

2. 数据库连接 URL

jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
  • useUnicode=true:支持 Unicode 字符

  • characterEncoding=UTF-8:使用 UTF-8 编码

  • serverTimezone=Asia/Shanghai:解决时区问题

3. Statement 与 PreparedStatement区别

特性StatementPreparedStatement
SQL 注入有风险防注入
执行效率每次执行都编译 SQL预编译,提高性能
参数绑定手动拼接setString/setInt
推荐程度高(实际项目都用这个)
  • Statement:直接拼接 SQL(有 SQL 注入风险)

  • PreparedStatement:预编译 SQL,防止注入,并提高执行效率(推荐)


五、在 Servlet 中调用

在 Java Web 中,可以将这个 JDBC 工具类放到 com.utils 包中,然后在 Servlet 中调用,例如:

@WebServlet("/search")
public class SearchServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 查询所有数据
        String sql = "SELECT * FROM qwe";
        String resultJson = Test.search(sql);

        // 设置响应类型为 JSON
        response.setContentType("application/json;charset=UTF-8");

        // 返回数据给前端
        response.getWriter().write(resultJson);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 如果需要支持 POST,可以在这里处理
        doGet(request, response);
    }
}

优化建议:

  1. 统一编码:在过滤器中设置 request.setCharacterEncoding("UTF-8")

  2. 返回 JSON 工具类:用 GsonJackson 代替手写 JSON。

  3. 异常处理:Servlet 里不要直接 printStackTrace(),建议记录到日志文件。


六、总结

       本文通过完整代码演示了如何用 JDBC 操作 MySQL 实现增删改查,并配合流程图、表结构图解释了其执行过程。
       在实际项目中,我们应结合 连接池 + PreparedStatement + DAO 封装,从而让代码更安全、更高效、更易维护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值