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

在 Java 开发中,数据库交互是核心功能之一。无论是用户信息存储、业务数据管理,还是系统日志记录,都需要通过 Java 程序与数据库建立连接并执行操作。本文将以 MySQL 数据库为例,从环境准备、数据库连接、基础 CRUD(创建 / 读取 / 更新 / 删除)操作三个维度,手把手教你实现 Java 与数据库的交互,适合 Java 初学者入门学习。

一、环境准备:搭建基础开发环境

在编写代码前,需确保本地已配置好以下工具和依赖,避免后续出现版本兼容或依赖缺失问题。

1.1 核心工具清单

JDK

Java 程序运行和编译的基础环境

1.8 及以上(LTS)

MySQL 数据库

提供数据存储服务的关系型数据库

5.7 或 8.0

IDE(开发工具)

编写、调试 Java 代码(如 IntelliJ IDEA)

社区版 / 旗舰版均可

MySQL JDBC 驱动

Java 程序与 MySQL 数据库通信的桥梁

8.0.30(适配 MySQL 8.0)

1.2 关键依赖配置(以 Maven 为例)

若使用 Maven 管理项目,需在 pom.xml 中添加 MySQL JDBC 驱动依赖(无需手动下载 JAR 包,Maven 会自动引入):

xml

<!-- MySQL JDBC 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
    <scope>runtime</scope> <!-- 运行时依赖,编译时无需参与 -->
</dependency>

1.3 提前创建数据库和表

为了后续测试 CRUD 操作,我们先在 MySQL 中创建一个示例数据库和表(以「用户表 user」为例):

  1. 打开 MySQL 命令行或可视化工具(如 Navicat),执行以下 SQL 创建数据库:sql
  2. 创建「用户表 user」,包含 id(主键)、username(用户名)、age(年龄)、email(邮箱)字段:sql

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

Java 通过 JDBC(Java Database Connectivity) 规范实现与数据库的连接。JDBC 本质是一套接口,由数据库厂商(如 MySQL)提供实现(即 JDBC 驱动)。

2.1 数据库连接核心步骤

  1. 加载 JDBC 驱动:MySQL 8.0 及以上版本无需显式加载(驱动会自动注册),低版本需通过 Class.forName("com.mysql.jdbc.Driver") 加载。
  2. 编写连接 URL:格式为 jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2。示例(MySQL 8.0):jdbc:mysql://localhost:3306/java_db?useSSL=false&serverTimezone=UTCuseSSL=false:禁用 SSL 加密(开发环境简化配置,生产环境需开启)。serverTimezone=UTC:设置时区(解决 MySQL 8.0 时区报错问题)。
  3. 获取数据库连接:通过 DriverManager.getConnection(url, username, password) 方法,传入数据库用户名(如 root)和密码(如你设置的 123456)。
  4. 关闭资源:连接、语句、结果集使用后需关闭(避免资源泄漏),建议用 try-with-resources(自动关闭资源)。

2.2 封装连接工具类(复用代码)

为了避免重复编写连接逻辑,我们封装一个 DBUtil 工具类,提供获取连接和关闭资源的方法:

java

import java.sql.*;

/**
 * 数据库连接工具类
 */
public class DBUtil {
    // 数据库连接信息(根据你的本地配置修改)
    private static final String URL = "jdbc:mysql://localhost:3306/java_db?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root"; // 你的 MySQL 用户名
    private static final String PASSWORD = "123456"; // 你的 MySQL 密码

    /**
     * 获取数据库连接
     * @return Connection 连接对象(null 表示连接失败)
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            // MySQL 8.0 无需显式加载驱动,底层自动注册
            conn = DriverManager.getConnection(URL, USER, PASSWORD);
            System.out.println("数据库连接成功!");
        } catch (SQLException e) {
            System.out.println("数据库连接失败!");
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭资源(Connection + Statement + ResultSet)
     * @param conn 连接对象
     * @param stmt 语句对象(执行 SQL 用)
     * @param rs 结果集对象(查询用)
     */
    public static void closeResources(Connection conn, Statement stmt, ResultSet rs) {
        // 关闭顺序:ResultSet → Statement → Connection(后创建的先关闭)
        try {
            if (rs != null) rs.close();
            if (stmt != null) stmt.close();
            if (conn != null) conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 重载:关闭无 ResultSet 的资源(如增、删、改操作)
    public static void closeResources(Connection conn, Statement stmt) {
        closeResources(conn, stmt, null);
    }
}

测试连接是否成功:

java

public class TestDBConnection {
    public static void main(String[] args) {
        // 调用工具类获取连接(测试用)
        Connection conn = DBUtil.getConnection();
        // 关闭连接
        DBUtil.closeResources(conn, null);
    }
}

若控制台输出「数据库连接成功!」,说明连接配置无误。

三、基础 CRUD 操作实现

CRUD 是数据库最核心的 four 种操作,对应 Java 代码需通过 Statement 或 PreparedStatement 执行 SQL(推荐用 PreparedStatement,可避免 SQL 注入风险)。

以下所有操作均基于「user 表」,先定义一个 User 实体类(与表字段对应,封装数据):

java

/**
 * User 实体类(与数据库 user 表字段对应)
 */
public class User {
    private Integer id;       // 对应表中 id 字段
    private String username;  // 对应表中 username 字段
    private Integer age;      // 对应表中 age 字段
    private String email;     // 对应表中 email 字段

    // 无参构造(必要,用于反射实例化)
    public User() {}

    // 有参构造(除 id,因为 id 是自增的)
    public User(String username, Integer age, String email) {
        this.username = username;
        this.age = age;
        this.email = email;
    }

    // Getter 和 Setter 方法(用于访问和修改私有属性)
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }

    // toString 方法(用于打印 User 对象信息)
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

3.1 新增操作(Create):向表中插入数据

需求:向 user 表插入一条用户数据(如 username=「张三」,age=25,email=「zhangsan@xxx.com」)。

实现代码

java

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 新增用户操作(Create)
 */
public class UserCreate {
    public static void main(String[] args) {
        // 1. 获取数据库连接
        Connection conn = DBUtil.getConnection();
        PreparedStatement pstmt = null;

        try {
            // 2. 编写 SQL(? 是占位符,避免 SQL 注入)
            String sql = "INSERT INTO user (username, age, email) VALUES (?, ?, ?)";
            
            // 3. 创建 PreparedStatement 对象(传入 SQL)
            pstmt = conn.prepareStatement(sql);
            
            // 4. 给占位符赋值(索引从 1 开始,对应 SQL 中 ? 的顺序)
            pstmt.setString(1, "张三");   // 第一个 ? 赋值为 username
            pstmt.setInt(2, 25);         // 第二个 ? 赋值为 age
            pstmt.setString(3, "zhangsan@xxx.com"); // 第三个 ? 赋值为 email
            
            // 5. 执行 SQL(新增/删除/修改用 executeUpdate(),返回受影响的行数)
            int rows = pstmt.executeUpdate();
            
            // 6. 判断执行结果
            if (rows > 0) {
                System.out.println("新增用户成功!受影响行数:" + rows);
            } else {
                System.out.println("新增用户失败!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7. 关闭资源
            DBUtil.closeResources(conn, pstmt);
        }
    }
}

验证结果:打开 MySQL 可视化工具,查询 user 表,若出现「张三」的记录,则新增成功。

3.2 查询操作(Read):从表中读取数据

需求:两种常见查询场景:

  1. 查询单条数据:根据 id 查询指定用户。
  2. 查询所有数据:查询 user 表中所有用户。

3.2.1 查询单条数据(按 id 查询)

java

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 查询单条用户数据(Read - 按 id 查询)
 */
public class UserReadSingle {
    public static void main(String[] args) {
        Connection conn = DBUtil.getConnection();
        PreparedStatement pstmt = null;
        ResultSet rs = null; // 存储查询结果的对象

        try {
            // 1. 编写 SQL(根据 id 查询)
            String sql = "SELECT id, username, age, email FROM user WHERE id = ?";
            
            // 2. 创建 PreparedStatement 并赋值
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, 1); // 查询 id=1 的用户(需确保该 id 存在)
            
            // 3. 执行 SQL(查询用 executeQuery(),返回 ResultSet)
            rs = pstmt.executeQuery();
            
            // 4. 解析 ResultSet(判断是否有数据,并用 next() 移动指针)
            if (rs.next()) {
                // 根据字段名获取数据(推荐用字段名,避免字段顺序变化导致错误)
                Integer id = rs.getInt("id");
                String username = rs.getString("username");
                Integer age = rs.getInt("age");
                String email = rs.getString("email");
                
                // 封装成 User 对象
                User user = new User();
                user.setId(id);
                user.setUsername(username);
                user.setAge(age);
                user.setEmail(email);
                
                // 打印结果
                System.out.println("查询到的用户:" + user);
            } else {
                System.out.println("未查询到 id=1 的用户!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源(包含 ResultSet)
            DBUtil.closeResources(conn, pstmt, rs);
        }
    }
}

3.2.2 查询所有数据

java

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 查询所有用户数据(Read - 查全部)
 */
public class UserReadAll {
    public static void main(String[] args) {
        Connection conn = DBUtil.getConnection();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        List<User> userList = new ArrayList<>(); // 存储所有用户的集合

        try {
            // 1. 编写 SQL(查询所有字段)
            String sql = "SELECT id, username, age, email FROM user";
            
            // 2. 创建 PreparedStatement(无占位符,无需赋值)
            pstmt = conn.prepareStatement(sql);
            
            // 3. 执行 SQL
            rs = pstmt.executeQuery();
            
            // 4. 循环解析 ResultSet(next() 返回 false 时表示无更多数据)
            while (rs.next()) {
                // 封装 User 对象
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setAge(rs.getInt("age"));
                user.setEmail(rs.getString("email"));
                
                // 添加到集合中
                userList.add(user);
            }
            
            // 5. 打印结果
            if (userList.isEmpty()) {
                System.out.println("表中无用户数据!");
            } else {
                System.out.println("查询到的所有用户:");
                for (User user : userList) {
                    System.out.println(user);
                }
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.closeResources(conn, pstmt, rs);
        }
    }
}

3.3 更新操作(Update):修改表中数据

需求:将 id=1 的用户年龄修改为 26,邮箱修改为「**********」。

实现代码

java

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 更新用户操作(Update)
 */
public class UserUpdate {
    public static void main(String[] args) {
        Connection conn = DBUtil.getConnection();
        PreparedStatement pstmt = null;

        try {
            // 1. 编写 SQL(修改 age 和 email,按 id 条件筛选)
            String sql = "UPDATE user SET age = ?, email = ? WHERE id = ?";
            
            // 2. 创建 PreparedStatement 并赋值
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, 26); // 第一个 ?:新年龄
            pstmt.setString(2, "**********"); // 第二个 ?:新邮箱
            pstmt.setInt(3, 1); // 第三个 ?:修改 id=1 的用户
            
            // 3. 执行 SQL(用 executeUpdate())
            int rows = pstmt.executeUpdate();
            
            // 4. 判断结果
            if (rows > 0) {
                System.out.println("更新用户成功!受影响行数:" + rows);
            } else {
                System.out.println("更新失败(可能 id 不存在)!");
            }

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

3.4 删除操作(Delete):删除表中数据

需求:删除 id=1 的用户数据。

实现代码

java

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 删除用户操作(Delete)
 */
public class UserDelete {
    public static void main(String[] args) {
        Connection conn = DBUtil.getConnection();
        PreparedStatement pstmt = null;

        try {
            // 1. 编写 SQL(按 id 删除)
            String sql = "DELETE FROM user WHERE id = ?";
            
            // 2. 创建 PreparedStatement 并赋值
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, 1); // 删除 id=1 的用户
            
            // 3. 执行 SQL
            int rows = pstmt.executeUpdate();
            
            // 4. 判断结果
            if (rows > 0) {
                System.out.println("删除用户成功!受影响行数:" + rows);
            } else {
                System.out.println("删除失败(可能 id 不存在)!");
            }

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

四、常见问题与注意事项

  1. 连接失败报错:检查 MySQL 是否启动(Windows 用 net start mysql,Linux 用 systemctl status mysql)。确认 URL 中的「主机地址、端口号、数据库名」是否正确(默认端口 3306)。检查用户名和密码是否与本地 MySQL 配置一致。
  2. SQL 注入风险:严禁使用 Statement 执行动态 SQL(如 String sql = "SELECT * FROM user WHERE username = '" + username + "'"),恶意用户可通过输入 ' OR '1'='1 绕过验证。必须使用 PreparedStatement 的占位符(?)赋值,驱动会自动对参数进行转义,避免 SQL 注入。
  3. 资源泄漏问题:连接、Statement、ResultSet 是稀缺资源,必须关闭(即使出现异常)。推荐使用 try-with-resources 语法(Java 7+),无需手动调用 close(),示例:java
  4. 时区报错(MySQL 8.0):若出现 The server time zone value 'XXX' is unrecognized,需在 URL 中添加 serverTimezone=UTC 或 serverTimezone=Asia/Shanghai(国内推荐后者)。

五、进阶方向

本文讲解的是 JDBC 原生操作,实际开发中会使用更高效的框架简化代码:

  • MyBatis:半自动化 ORM 框架,减少 JDBC 冗余代码,支持 XML / 注解写 SQL。
  • Spring JDBC:Spring 提供的轻量级封装,核心是 JdbcTemplate,无需手动关闭资源。
  • Spring Data JPA:全自动化 ORM 框架,基于 JPA 规范,无需编写 SQL(简单场景),适合快速开发。

若你已掌握本文的基础操作,可进一步学习这些框架,提升开发效率。

至此,Java 链接数据库与基础 CRUD 操作已全部讲解完毕。建议大家动手实践每一步,遇到报错时对照「常见问题」排查,逐步理解数据库交互的核心逻辑。

tl917.hsd-stone.com

eflv3.hsd-stone.com

ur1cb.hsd-stone.com

31hck.hsd-stone.com

x4uuq.hsd-stone.com

ckp18.hsd-stone.com

ydiczgjzhhd2.www.sxkjsm.com

4gt39swalf2.www.sxkjsm.com

t.www.sxkjsm.com

yosc3xw.www.sxkjsm.com

mrhr3o5k65llhf.www.sxkjsm.com

qkk21dp1zby.www.sxkjsm.com

hr5qpq7kna265.www.sxkjsm.com

kqqcdgupxpau2aw5t.sxkjsm.com

u.www.sxkjsm.com

m3bobuay.www.sxkjsm.com

ygcx.sxkjsm.com

wap.share.wuxiangxing.com

6www.share.wuxiangxing.com

mobile.shop.wuxiangxing.com

全部评论

相关推荐

叁六玖:我靠,对我来说是巨款了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务