杰瑞科技汇

Java数据库实例PDF,如何高效实践?

Java 数据库操作完整指南 (实例详解)

目录

  1. 引言:为什么需要 Java 连接数据库?
  2. 核心概念:JDBC (Java Database Connectivity)
    • 什么是 JDBC?
    • JDBC 四大核心组件
  3. 准备工作:环境配置
    • 安装 JDK
    • 添加数据库驱动
  4. 第一步:建立数据库连接
    • 加载驱动
    • 获取连接
    • 代码实例
  5. 第二步:执行 SQL 语句 (核心操作)
    • Statement - 执行静态 SQL
      • 增、删、改 代码实例
      • 查询 代码实例
    • PreparedStatement - 执行动态 SQL (推荐)
      • 为什么推荐使用 PreparedStatement
      • 增、删、改 代码实例
      • 查询 代码实例
    • ResultSet - 处理查询结果
  6. 第三步:处理事务
    • 什么是事务?
    • ACID 特性
    • 事务管理代码实例
  7. 第四步:资源释放 (至关重要)
    • 为什么必须释放资源?
    • try-with-resources 语句 (最佳实践)
  8. 完整项目示例:一个简单的用户管理系统
    • 数据库表设计
    • 项目结构
    • 完整代码实现
  9. 现代替代方案:JPA / Hibernate

    JDBC vs. JPA/Hibernate

    Java数据库实例PDF,如何高效实践?-图1
    (图片来源网络,侵删)
  10. 总结与最佳实践

引言:为什么需要 Java 连接数据库?

在大多数企业级应用中,数据都需要被持久化存储,数据库是存储和管理数据的标准方式,Java 作为一种强大的后端语言,必须具备与数据库交互的能力,以实现数据的增、删、改、查,从而构建动态、功能丰富的应用程序。

核心概念:JDBC (Java Database Connectivity)

什么是 JDBC?

JDBC (Java Database Connectivity) 是 Java API 的一部分,它定义了一套标准,允许 Java 程序与各种关系型数据库(如 MySQL, Oracle, SQL Server)进行交互,你可以把它想象成 Java 和数据库之间的“翻译官”或“桥梁”。

JDBC 四大核心组件

  1. Driver (驱动):由数据库厂商提供,负责将 JDBC 的调用转换为特定数据库的底层协议。mysql-connector-java.jar MySQL 的 JDBC 驱动。
  2. Connection (连接):代表与数据库的一个会话,通过连接,你可以向数据库发送命令并接收结果。
  3. Statement / PreparedStatement:用于向数据库发送 SQL 语句的“载体”。
    • Statement: 用于执行静态的、不带参数的 SQL。
    • PreparedStatement: 用于执行动态的、带参数的 SQL,强烈推荐使用,因为它更安全、更高效。
  4. ResultSet (结果集):当执行查询语句后,数据库返回的结果被封装在 ResultSet 对象中,它像一个指向数据行的“光标”,你可以遍历它来获取所有查询到的数据。

准备工作:环境配置

安装 JDK

确保你的系统已经安装了 Java Development Kit (JDK),并配置了 JAVA_HOMEPATH 环境变量。

添加数据库驱动

你需要下载你所使用的数据库的 JDBC 驱动程序(通常是一个 .jar 文件),并将其添加到你的 Java 项目的类路径中。

Java数据库实例PDF,如何高效实践?-图2
(图片来源网络,侵删)
  • 对于 Maven 项目:在 pom.xml 文件中添加依赖。
    <!-- MySQL 8.x 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version> <!-- 使用合适的版本 -->
    </dependency>
  • 对于普通 Java 项目:将下载的 .jar 文件复制到项目的 lib 目录下,并添加到构建路径中。

第一步:建立数据库连接

这是所有数据库操作的第一步。

加载驱动

// 对于 MySQL 8.x
Class.forName("com.mysql.cj.jdbc.Driver");
// 对于 MySQL 5.x
// Class.forName("com.mysql.jdbc.Driver");

注意:从 JDBC 4.0 (Java 6) 开始,驱动加载步骤通常是可选的,因为驱动会自动注册,但显式写出可以确保代码的清晰和兼容性。

获取连接

使用 DriverManager 类的 getConnection() 方法。

String url = "jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC";
String user = "your_username";
String password = "your_password";
Connection connection = DriverManager.getConnection(url, user, password);
  • URL 格式jdbc:mysql://主机名:端口号/数据库名?参数
    • localhost: 数据库所在的主机地址。
    • 3306: MySQL 的默认端口号。
    • your_database_name: 你要连接的数据库。
    • useSSL=false: 禁用 SSL(用于本地开发)。
    • serverTimezone=UTC: 设置服务器时区,避免警告。

代码实例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "password";
    public static Connection getConnection() {
        Connection connection = null;
        try {
            // 1. 加载驱动 (可选但推荐)
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 获取连接
            connection = DriverManager.getConnection(URL, USER, PASSWORD);
            System.out.println("数据库连接成功!");
        } catch (ClassNotFoundException e) {
            System.err.println("找不到 JDBC 驱动类。");
            e.printStackTrace();
        } catch (SQLException e) {
            System.err.println("数据库连接失败。");
            e.printStackTrace();
        }
        return connection;
    }
}

第二步:执行 SQL 语句

这是数据库操作的核心,分为更新(增删改)和查询。

Java数据库实例PDF,如何高效实践?-图3
(图片来源网络,侵删)

Statement - 执行静态 SQL

增、删、改 代码实例
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
public class StatementUpdateExample {
    public static void main(String[] args) {
        String sql = "INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com')";
        // 使用 try-with-resources 自动关闭 Statement 和 Connection
        try (Connection conn = DBConnection.getConnection();
             Statement stmt = conn.createStatement()) {
            // executeUpdate() 返回受影响的行数
            int affectedRows = stmt.executeUpdate(sql);
            System.out.println("成功插入 " + affectedRows + " 行数据。");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
查询 代码实例
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class StatementQueryExample {
    public static void main(String[] args) {
        String sql = "SELECT id, name, email FROM users";
        try (Connection conn = DBConnection.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) { // executeQuery() 用于查询
            System.out.println("ID\tName\tEmail");
            System.out.println("--------------------");
            // 遍历结果集
            while (rs.next()) {
                // 通过列名或列索引获取数据
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "\t" + name + "\t" + email);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

PreparedStatement - 执行动态 SQL (推荐)

PreparedStatement 预先编译 SQL 语句,并使用 作为占位符,它可以防止 SQL 注入攻击,并且对于重复执行的 SQL,效率更高。

增、删、改 代码实例
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class PreparedStatementUpdateExample {
    public static void main(String[] args) {
        String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数 (索引从 1 开始)
            pstmt.setString(1, "Jane Smith");
            pstmt.setString(2, "jane.smith@example.com");
            int affectedRows = pstmt.executeUpdate();
            System.out.println("成功插入 " + affectedRows + " 行数据。");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
查询 代码实例
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PreparedStatementQueryExample {
    public static void main(String[] args) {
        String sql = "SELECT * FROM users WHERE id = ?";
        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数
            pstmt.setInt(1, 1); // 查询 id 为 1 的用户
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    System.out.println("找到用户: ID=" + rs.getInt("id") 
                                     + ", Name=" + rs.getString("name"));
                } else {
                    System.out.println("未找到 ID 为 1 的用户。");
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

ResultSet - 处理查询结果

ResultSet 提供了多种方法来获取不同类型的数据:

  • getInt(columnName): 获取整数
  • getString(columnName): 获取字符串
  • getDate(columnName): 获取日期
  • getBoolean(columnName): 获取布尔值
  • 也可以使用列索引,如 getString(1)

第三步:处理事务

事务是一组 SQL 操作,它们要么全部成功,要么全部失败,这对于保证数据一致性至关重要(银行转账)。

ACID 特性

  • 原子性: 事务是一个不可分割的工作单位。
  • 一致性: 事务必须使数据库从一个一致性状态变到另一个一致性状态。
  • 隔离性: 一个事务的执行不能被其他事务干扰。
  • 持久性: 一个事务一旦提交,它对数据库中数据的改变就是永久的。

事务管理代码实例

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TransactionExample {
    public static void main(String[] args) {
        Connection conn = null;
        try {
            conn = DBConnection.getConnection();
            // 关闭自动提交,开启手动事务
            conn.setAutoCommit(false);
            // 转账操作:从 A 账户扣款,给 B 账户加款
            String sql1 = "UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice'";
            String sql2 = "UPDATE accounts SET balance = balance + 100 WHERE name = 'Bob'";
            try (PreparedStatement pstmt1 = conn.prepareStatement(sql1);
                 PreparedStatement pstmt2 = conn.prepareStatement(sql2)) {
                pstmt1.executeUpdate();
                // 模拟一个错误
                // int x = 1 / 0; // 如果取消注释,事务将回滚
                pstmt2.executeUpdate();
                // 如果所有操作都成功,提交事务
                conn.commit();
                System.out.println("转账成功!");
            } catch (SQLException e) {
                // 如果发生异常,回滚事务
                conn.rollback();
                System.err.println("转账失败,事务已回滚。");
                e.printStackTrace();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                try {
                    // 恢复自动提交模式
                    conn.setAutoCommit(true);
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

第四步:资源释放 (至关重要)`

数据库连接、StatementResultSet 都是宝贵的系统资源,使用完毕后必须关闭,否则会导致连接泄露,最终使应用程序崩溃。

为什么必须释放资源?

数据库服务器能同时建立的连接数是有限的,如果程序不关闭连接,这些连接会被一直占用,直到程序结束,导致其他用户无法连接。

try-with-resources 语句 (最佳实践)

从 Java 7 开始,推荐使用 try-with-resources 语句,它会在 try 块执行完毕后,自动关闭实现了 AutoCloseable 接口的对象(如 Connection, Statement, ResultSet),无需手动调用 close()

示例 (前面所有例子都已使用此模式)

// try-with-resources 会自动 conn, stmt, rs
try (Connection conn = DBConnection.getConnection();
     PreparedStatement pstmt = conn.prepareStatement(sql);
     ResultSet rs = pstmt.executeQuery()) {
    // ... 执行操作 ...
} catch (SQLException e) {
    // ... 异常处理 ...
}
// conn, pstmt, rs 都已被自动关闭

完整项目示例:一个简单的用户管理系统

数据库表设计

CREATE DATABASE IF NOT EXISTS javadb;
USE javadb;
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

项目结构

UserManagementSystem/
├── src/
│   └── com/
│       └── example/
│           ├── dao/
│           │   └── UserDAO.java
│           ├── model/
│           │   └── User.java
│           └── Main.java
├── lib/
│   └── mysql-connector-java-8.0.28.jar (手动添加时)
└── pom.xml (Maven 项目)

完整代码实现

User.java (模型类)

package com.example.model;
import java.util.Date;
public class User {
    private int id;
    private String name;
    private String email;
    private Date createdAt;
    // Getters and Setters
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public Date getCreatedAt() { return createdAt; }
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", createdAt=" + createdAt +
                '}';
    }
}

UserDAO.java (数据访问对象)

package com.example.dao;
import com.example.model.User;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class UserDAO {
    // 添加用户
    public void addUser(User user) {
        String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, user.getName());
            pstmt.setString(2, user.getEmail());
            pstmt.executeUpdate();
            System.out.println("用户添加成功: " + user.getName());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 根据ID查找用户
    public User getUserById(int id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        User user = null;
        try (Connection conn = DBConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setInt(1, id);
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    user = new User();
                    user.setId(rs.getInt("id"));
                    user.setName(rs.getString("name"));
                    user.setEmail(rs.getString("email"));
                    user.setCreatedAt(rs.getTimestamp("created_at"));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return user;
    }
    // 获取所有用户
    public List<User> getAllUsers() {
        List<User> users = new ArrayList<>();
        String sql = "SELECT * FROM users";
        try (Connection conn = DBConnection.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            while (rs.next()) {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setEmail(rs.getString("email"));
                user.setCreatedAt(rs.getTimestamp("created_at"));
                users.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return users;
    }
}

Main.java (主程序)

package com.example;
import com.example.dao.UserDAO;
import com.example.model.User;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        UserDAO userDAO = new UserDAO();
        // 1. 添加一个新用户
        User newUser = new User();
        newUser.setName("Alice");
        newUser.setEmail("alice@example.com");
        userDAO.addUser(newUser);
        // 2. 获取并显示所有用户
        System.out.println("\n--- 所有用户列表 ---");
        List<User> allUsers = userDAO.getAllUsers();
        for (User user : allUsers) {
            System.out.println(user);
        }
        // 3. 根据ID查找用户
        System.out.println("\n--- 查找ID为1的用户 ---");
        User foundUser = userDAO.getUserById(1);
        if (foundUser != null) {
            System.out.println(foundUser);
        } else {
            System.out.println("未找到该用户。");
        }
    }
}

现代替代方案:JPA / Hibernate

虽然 JDBC 是基础,但在现代开发中,直接编写大量的 JDBC 代码会变得繁琐且容易出错,出现了 ORM (Object-Relational Mapping) 框架。

  • JPA (Java Persistence API): Java EE 提供的一套 ORM 规范,它定义了接口。
  • Hibernate: 是 JPA 规范最流行的实现,你通过操作 Java 对象(如 User 对象),Hibernate 会自动将其转换为 SQL 语句并执行。

JPA/Hibernate 的优势:

  • 减少样板代码: 无需手动编写 INSERT, UPDATE, DELETE 语句。
  • 提高开发效率: 更关注业务逻辑,而非 SQL 细节。
  • 数据库无关性: 更换数据库(如从 MySQL 换成 PostgreSQL)时,代码改动很小。
  • 强大的查询功能: 提供 HQL (Hibernate Query Language) 和 Criteria API。

对于大型项目,强烈建议学习并使用 JPA/Hibernate 或 MyBatis 等框架。

总结与最佳实践

  1. 始终使用 PreparedStatement: 除非有特殊需求,否则永远不要使用 Statement,它能有效防止 SQL 注入,并且性能更好。
  2. 永远使用 try-with-resources: 自动管理资源,避免内存和连接泄露。
  3. 合理使用事务: 对于需要保证数据一致性的操作(如转账、下单),务必使用事务。
  4. 使用 DAO 模式: 将数据库访问逻辑与业务逻辑分离,使代码结构更清晰、更易于维护。
  5. 考虑使用 ORM 框架: 对于复杂项目,JPA/Hibernate 可以极大地提高开发效率和代码质量。
  6. 配置连接池: 在生产环境中,不要直接使用 DriverManager,应使用如 HikariCP, C3P0 等连接池来管理数据库连接,以提高性能和稳定性。

希望这份详细的指南能帮助你掌握 Java 数据库操作!

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