下载工作台
Java 编程实战

JDBC 与 MySQL 入门

试读上半部分 · 解锁后可读全文

第 11 章 · JDBC 与 MySQL 入门

本章目标:理解 JDBC 标准访问数据库的流程;使用 MySQL 驱动建立连接;掌握 PreparedStatement 防 SQL 注入;完成 CRUD 增删改查;了解 连接池概念与为何生产必须用池化。

学时建议:5~6 小时(含 2 小时跟练)

前置ch07 IO 与异常;ch08 Map 存查询结果。


11.1 JDBC 是什么

JDBC(Java Database Connectivity)是 Java 访问关系型数据库的统一 API:

Java 应用
  → JDBC API(Connection, Statement, ResultSet)
  → 数据库驱动(如 mysql-connector-j)
  → MySQL Server
组件作用
DriverManager获取连接(入门)
Connection数据库会话
Statement / PreparedStatement执行 SQL
ResultSet查询结果集

本教程使用虚构教学库 db.example.com,本地可用 Docker 或本机 MySQL 模拟。


11.2 环境准备

Maven 依赖pom.xml):

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.3.0</version>
</dependency>

连接 URL 格式

jdbc:mysql://db.example.com:3306/toolkit_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
参数说明
hostdb.example.com127.0.0.1
port默认 3306
database库名,如 toolkit_db
serverTimezone避免时区警告
useSSL教学环境关闭以简化;生产环境必须开启 SSL 或走内网隔离
安全提示useSSL=false 仅限本机教学库。连接生产或云上数据库时去掉该参数(MySQL 8 默认 useSSL=true),并配合环境变量/密钥管理读取凭据。

切勿在代码中硬编码真实生产密码;练习从环境变量读取:

String url = System.getenv("DB_URL");
String user = System.getenv("DB_USER");
String pass = System.getenv("DB_PASS");

11.3 第一次连接

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class JdbcConnectDemo {
    public static void main(String[] args) {
        String url = "jdbc:mysql://127.0.0.1:3306/toolkit_db"
            + "?useSSL=false&serverTimezone=Asia/Shanghai";
        String user = "learn_user";
        String password = "learn_pass";

        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            System.out.println("连接成功: " + conn.getMetaData().getDatabaseProductName());
        } catch (SQLException e) {
            System.err.println("连接失败: " + e.getMessage());
        }
    }
}

try-with-resourcesConnection 实现 AutoCloseable,块结束自动关闭。


11.4 建表与样本数据

在 MySQL 客户端执行(教学库):

CREATE DATABASE IF NOT EXISTS toolkit_db
  DEFAULT CHARACTER SET utf8mb4;

USE toolkit_db;

CREATE TABLE IF NOT EXISTS products (
    id       BIGINT PRIMARY KEY AUTO_INCREMENT,
    sku      VARCHAR(32)  NOT NULL UNIQUE,
    title    VARCHAR(128) NOT NULL,
    price    DECIMAL(10,2) NOT NULL,
    stock    INT NOT NULL DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO products (sku, title, price, stock) VALUES
('BK-001', 'Java 基础', 59.90, 120),
('BK-002', 'Web 开发', 79.00, 45),
('BK-003', '数据分析', 45.00, 89);

11.5 PreparedStatement 查询

永远优先 PreparedStatement,参数绑定防 SQL 注入:

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class ProductQuery {

    record Product(long id, String sku, String title, double price, int stock) {}

    public List<Product> findByMinPrice(Connection conn, double minPrice) throws SQLException {
        String sql = "SELECT id, sku, title, price, stock FROM products WHERE price >= ?";
        List<Product> list = new ArrayList<>();

        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setDouble(1, minPrice);
            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    list.add(new Product(
                        rs.getLong("id"),
                        rs.getString("sku"),
                        rs.getString("title"),
                        rs.getDouble("price"),
                        rs.getInt("stock")
                    ));
                }
            }
        }
        return list;
    }
}
ResultSet 方法类型
getLong("id")BIGINT
getString("sku")VARCHAR
getDouble("price")DECIMAL
getTimestamp("created_at")TIMESTAMP

11.6 INSERT 增删改

public int insertProduct(Connection conn, String sku, String title,
                         double price, int stock) throws SQLException {
    String sql = "INSERT INTO products (sku, title, price, stock) VALUES (?, ?, ?, ?)";

    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setString(1, sku);
        ps.setString(2, title);
        ps.setDouble(3, price);
        ps.setInt(4, stock);
        return ps.executeUpdate();  // 影响行数
    }
}

public int updateStock(Connection conn, String sku, int newStock) throws SQLException {
    String sql = "UPDATE products SET stock = ? WHERE sku = ?";
    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setInt(1, newStock);
        ps.setString(2, sku);
        return ps.executeUpdate();
    }
}

public int deleteBySku(Connection conn, String sku) throws SQLException {
    String sql = "DELETE FROM products WHERE sku = ?";
    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setString(1, sku);
        return ps.executeUpdate();
    }
}
方法用途
executeQuery()SELECT,返回 ResultSet
executeUpdate()INSERT/UPDATE/DELETE,返回行数
execute()任意,需判断类型

11.7 获取自增主键

String sql = "INSERT INTO products (sku, title, price, stock) VALUES (?, ?, ?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
    ps.setString(1, "BK-004");
    ps.setString(2, "算法入门");
    ps.setDouble(3, 68.0);
    ps.setInt(4, 30);
    ps.executeUpdate();

    try (ResultSet keys = ps.getGeneratedKeys()) {
        if (keys.next()) {
            long newId = keys.getLong(1);
            System.out.println("新 ID: " + newId);
        }
    }
}

11.8 事务入门

多条 SQL 需原子性时用事务:

conn.setAutoCommit(false);
try {
    updateStock(conn, "BK-001", 100);

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。