九、JDBC 操作 MySQL 数据库

1. 创建数据源

1.1 什么是数据源

  1. 数据源(DataSource) 用于管理数据库连接信息,通过数据源可以获取与 MySQL 数据库的连接对象 Connection。
  2. 在 JDBC 中,使用 MysqlDataSource 配置数据库连接地址、用户名和密码。
  3. 先启动 MySQL 服务,再执行 Java 程序,否则可能出现连接失败。
  4. JDBC URL 中的数据库名称必须正确,且数据库需要事先创建。
  5. DataSource 是接口,MysqlDataSource 是 MySQL 驱动提供的实现类。接口变量不能直接调用实现类特有的 setUrl()、setUser() 和 setPassword() 方法。
  6. 数据库连接地址、用户名和密码必须与本机配置一致。
  7. 使用 JDBC 前,需要在项目中引入 MySQL Connector/J 驱动,否则可能出现找不到驱动类的错误。

1.2 导入相关类

java 复制代码
import javax.sql.DataSource;
//数据库接口,mysql/sqlsever等多种数据库,用的使用要向上/下转型

import com.mysql.cj.jdbc.MysqlDataSource;
//这里使用的是mysql数据库。MysqlDataSource是DataSource其中一个子类

import java.sql.Connection;
//数据库连接类

import java.sql.SQLException;
//sql语句会有异常,所以包导入异常类

1.3 创建并配置数据源

java 复制代码
// 1. 创建数据源对象
DataSource dataSource = new MysqlDataSource();
//使用mysql数据库子类,向上转型为DataSource类

// 2. 配置数据库连接地址
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java119?characterEncoding=utf8&useSSL=false");
//(MysqlDataSource)dataSource:将dataSource对象强转成MysqlDataSource类,调用MysqlDataSource子类中特有的setUrl方法,设置要访问的数据库地址,编码集,私密性

// 3. 设置数据库用户名
((MysqlDataSource) dataSource).setUser("root");

// 4. 设置数据库密码
((MysqlDataSource) dataSource).setPassword("2222");

// 5. 获取数据库连接对象
Connection connection = dataSource.getConnection();
/*
	DataSource:连接配置保存数据库地址、账号和密码等信息。
	Connection:通信通道建立 Java 程序与 MySQL 之间的连接,让程序能够提交 SQL。
	PreparedStatement:SQL 执行工具,通过连接创建,用来设置 SQL 参数并执行 SQL。 
*/

1.4 JDBC URL 组成

java 复制代码
jdbc:mysql://127.0.0.1:3306/java119?characterEncoding=utf8&useSSL=false
组成部分 含义
jdbc:mysql 使用 MySQL 的 JDBC 驱动
127.0.0.1 数据库服务器地址,本机 IP
3306 MySQL 默认端口
java119 要连接的数据库名称
characterEncoding=utf8 指定字符编码
useSSL=false 禁用 SSL 连接,私密,禁止他人访问

2. 构造 SQL 语句

2.1 获取用户输入

  • 使用 Scanner 获取用户输入的学号和姓名。
java 复制代码
import java.util.Scanner;

// 创建输入对象
Scanner scanner = new Scanner(System.in);

// 输入学号
System.out.println("请输入学号:");
int id = scanner.nextInt();

// 输入姓名
System.out.println("请输入姓名:");
String name = scanner.next();

2.2 SQL 语句的构造方式

方式一:直接编写固定 SQL

java 复制代码
String sql = "INSERT INTO student VALUES (4, '赵六')";
  • 这种方式适用于固定数据,但无法直接满足动态输入的需求。

方式二:字符串拼接

java 复制代码
String sql = "INSERT INTO student VALUES (     " + id + "  ,    '   " + name + "  ' )";
											//	     4, '赵六'
  • 这种方式可以将用户输入拼接到 SQL 中,但存在 SQL 注入风险,并且需要注意字符串引号问题。

方式三:使用占位符(推荐)

java 复制代码
String sql = "INSERT INTO student VALUES (?, ?)";
java 复制代码
? :代表占位符,数据库表中第一列是id第一个?就代表id列。
  • 第一个 ? 表示学号。
  • 第二个 ? 表示姓名。
  • 使用占位符可以将 SQL 结构与具体参数分开,后续通过 PreparedStatement 绑定参数。
  1. SQL 语句中的表名、字段名必须与数据库实际结构一致。

  2. 使用 INSERT INTO student VALUES (?, ?) 时,参数顺序必须与表中字段的顺序一致。

  3. 如果只插入指定字段,推荐明确写出字段名:

    javascript 复制代码
    String sql = "INSERT INTO student (id, name) VALUES (?, ?)";

    这样可以避免因表字段顺序变化而导致插入错误。

  4. SQL 字符串拼接虽然可以动态生成 SQL,但不推荐直接拼接用户输入的数据,容易引发 SQL 注入问题。

  5. PreparedStatement 中的 ? 用于表示参数值,不能直接代替表名、字段名或 SQL 关键字。


3. 预处理 SQL 语句

3.1 创建 PreparedStatement 对象

  • PreparedStatement 是 JDBC 提供的预处理 SQL 语句对象,可以设置 SQL 参数并执行 SQL。
java 复制代码
import java.sql.PreparedStatement;
 
PreparedStatement statement = connection.prepareStatement(sql)

/*
	将上述写的sql语句当成参数传进来进行预处理
	根据 SQL 创建预处理语句对象:statement  
	connection:已经建立的数据库连接对象。  
	prepareStatement(sql):调用方法,创建并返回一个预处理语句对象。
    statement:引用这个返回的对象,后续通过它设置参数和执行 SQL。
*/
  • 这里的 connection 是前面通过数据源获取的数据库连接对象,sql 是包含占位符的 INSERT INTO student VALUES (?, ?)语句。

3.2 设置占位符参数

java 复制代码
// 设置第一个占位符,学号从 1 开始编号
statement.setInt(1, id);

// 设置第二个占位符,姓名从 2 开始编号
statement.setString(2, name);

常用参数设置方法:

方法 作用
setInt(index, value) 设置整数参数
setString(index, value) 设置字符串参数
setDouble(index, value) 设置双精度浮点数参数
setBoolean(index, value) 设置布尔参数
setNull(index, sqlType) 设置 SQL 空值

注意: PreparedStatement 的参数下标从 1 开始,而不是从 0 开始。

3.3 预处理的优点

  1. 提高安全性: 使用参数绑定能够有效防范通过参数值进行的 SQL 注入。

  2. 方便传参: 无需手动拼接字符串和处理引号。

  3. 便于维护: SQL 结构与参数分离,代码更加清晰。

  4. 参数下标从 1 开始,而不是从 0 开始。

    java 复制代码
    statement.setInt(1, id);
    statement.setString(2, name);
  5. 参数设置方法需要与 Java 数据类型相匹配,例如整数使用 setInt(),字符串使用 setString()。

  6. 占位符的数量必须与实际绑定的参数数量对应。

  7. 参数绑定必须在执行 SQL 之前完成,否则可能出现参数未设置的异常。

  8. 使用 PreparedStatement 绑定参数能够有效防范 SQL 注入,但前提是将用户输入作为参数绑定,而不是先拼接进 SQL 字符串。


4. 将 SQL 语句发送到数据库服务器并执行

  1. executeUpdate() 不用于读取查询结果集。 执行 SELECT 查询通常使用 executeQuery()。
  2. executeUpdate() 返回受影响的记录数,不是布尔值,也不是查询结果。
  3. 返回值为 1 通常表示成功插入或修改了一条记录;返回值为 0 不一定表示程序报错,例如某些更新语句没有匹配到记录时就可能返回 0。
  4. 如果插入的主键已经存在,可能出现主键重复异常;如果字段不允许为空,也需要确保传入的数据满足约束。
  5. SQL 执行失败时,通常会抛出 SQLException,应通过异常处理定位问题。

4.1 执行 预处理后的SQL语句

java 复制代码
// 执行 INSERT、UPDATE、DELETE 等数据修改语句
int n = statement.executeUpdate();

// 输出受影响的记录数
System.out.println("n = " + n);
  • executeUpdate() 用于执行 INSERT、UPDATE、DELETE 等数据修改语句,也可以执行建表等不返回查询结果集的 SQL。
  • 返回值 n 通常表示受影响的记录数。例如,插入一条学生记录时,成功插入一条通常返回 1。

4.2 JDBC 常见执行方法

方法 适用场景 返回值
executeQuery() SELECT 查询 ResultSet 结果集
executeUpdate() INSERT、UPDATE、DELETE 等 int 受影响行数
execute() 不确定 SQL 类型或需要通用执行 boolean,表示是否返回结果集

执行流程:

  1. 将 SQL 语句交给 Connection 创建 PreparedStatement。
  2. 使用 setInt()、setString() 等方法绑定参数。
  3. 调用 executeUpdate() 执行语句。
  4. JDBC 驱动与数据库服务器通信,数据库执行 SQL 并返回执行结果。

5. 资源回收

5.1 为什么需要资源回收

  • JDBC 操作过程中会创建数据库连接和 SQL 语句对象。这些对象占用数据库连接、服务器会话或其他资源,因此使用结束后应及时释放。
java 复制代码
// 关闭 SQL 语句对象
statement.close();

// 关闭数据库连接
connection.close();
  • 原始示例还创建了 Scanner,如果不再使用,也可以关闭:

    scanner.close();

6. JDBC 操作 MySQL 完整示例

6.1插入语句

java 复制代码
import com.mysql.cj.jdbc.MysqlDataSource;// 导入 MySQL 数据源实现类,用于配置 MySQL 数据库连接
import javax.sql.DataSource;// 导入数据源接口,用于获取数据库连接
import java.sql.Connection;// 导入数据库连接接口,负责创建 SQL 语句对象和管理事务
import java.sql.PreparedStatement;// 导入预处理 SQL 语句接口,用于绑定参数和执行 SQL
import java.sql.SQLException;// 导入 SQL 异常类,用于处理数据库操作过程中发生的异常
import java.util.Scanner;

public class JdbcDemo {
    public static void main(String[] args) throws SQLException {
        Scanner scanner = new Scanner(System.in);

        // 1. 创建并配置 "数据源"
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java119?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource) dataSource).setUser("root");
        ((MysqlDataSource) dataSource).setPassword("2222");

        // 2. 依据上面的数据源, 对数据库服务器, 建立连接
        Connection connection = dataSource.getConnection();

        System.out.println("请输入学号: ");
        int id = scanner.nextInt();
        System.out.println("请输入姓名: ");
        String name = scanner.next();
        
        //3.构造sql语句
        String sql = "insert into student values(?, ?)";
        
		// 4.预处理:把 SQL 字符串转为 "sql语句对象"
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setInt(1, id);
        statement.setString(2, name);

        // 5. 执行语句对象 (把预处理过的 SQL 发送给数据库服务器)
        int n = statement.executeUpdate();
        System.out.println("n = " + n);

        // 6. 释放前面创建过的资源.
        statement.close();
        connection.close();
    }
}

本程序的执行步骤

  1. 创建数据源: 配置数据库地址、用户名和密码。
  2. 获取连接: 通过 getConnection() 获取数据库连接对象。
  3. 接收输入: 获取学生的学号和姓名。
  4. 构造 SQL: 使用 ? 占位符编写插入语句。
  5. 预处理和绑定参数: 创建 PreparedStatement,将输入数据绑定到占位符。
  6. 执行 SQL: 调用 executeUpdate() 插入数据。
  7. 释放资源: 关闭语句对象、数据库连接和输入对象。

注意

  • Connection 和 PreparedStatement 如果执行过程中发生异常,原代码可能无法执行到 close()。
  • INSERT INTO student VALUES (?, ?) 默认按表的字段顺序插入数据。更推荐明确写出字段名,例如 INSERT INTO student (id, name) VALUES (?, ?)。
  • setInt(1, id) 中的 1 是占位符的位置,不是学号;真正的学号来自变量 id。
  • executeUpdate() 返回的是受影响的记录数int类型,不是新插入记录的学号。

运行前提:

  • 已添加 MySQL Connector/J 驱动依赖。
  • MySQL 服务已经启动。
  • java119 数据库和 student 表已经存在。
  • student 表的字段顺序与插入的学号、姓名对应。
  • 数据库用户名、密码与本机实际配置一致。

6.2查询语句

java 复制代码
import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

public class JdbcDemo {
    public static void main(String[] args) throws SQLException {
        Scanner scanner = new Scanner(System.in);

        // 1. 创建并配置 "数据源"
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java119?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource) dataSource).setUser("root");
        ((MysqlDataSource) dataSource).setPassword("2222");

        // 2. 依据上面的数据源, 对数据库服务器, 建立连接
        Connection connection = dataSource.getConnection();

        System.out.println("请输入学号: ");
        int id = scanner.nextInt();
        System.out.println("请输入姓名: ");
        String name = scanner.next();

        // 3. 构造 SQL
        // String sql = "insert into student values(4, \"赵六\")";
        // String sql = "insert into student values(" + id + ", \"" + name + "\")";
        // System.out.println("拼装好的 SQL 为: " + sql);

        String sql = "insert into student values(?, ?)";

        // 4.预处理:实际上还需要把 SQL 字符串转为 "语句对象"
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setInt(1, id);
        statement.setString(2, name);

        // 5. 执行这个语句对象 (把预处理过的 SQL 发送给数据库服务器)
        int n = statement.executeUpdate();
        System.out.println("n = " + n);

        // 6. 释放前面创建过的资源.
        statement.close();
        connection.close();
    }
}

7. 本节总结

步骤 核心对象或方法 作用
1. 创建数据源 DataSource、MysqlDataSource 配置数据库连接信息
2. 构造 SQL String sql 定义要执行的 SQL 语句
3. 预处理 prepareStatement()、setInt()、setString() 创建语句对象并绑定参数
4. 执行 SQL executeUpdate() 将语句交由 JDBC 驱动执行并获取结果
5. 资源回收 close()、try-with-resources 释放语句对象、数据库连接等资源

记忆口诀: 创建数据源 → 构造 SQL → 预处理并绑定参数 → 执行 SQL → 释放资源。

8. 常见错误与排查

常见问题 可能原因 排查方法
找不到 MysqlDataSource 未引入 MySQL 驱动依赖 检查 Connector/J 依赖
数据库连接失败 MySQL 未启动、URL 错误或账号密码不正确 检查服务状态和连接配置
找不到数据库 数据库名称错误或数据库尚未创建 执行 SHOW DATABASES;
找不到数据表 表名错误或表尚未创建 执行 SHOW TABLES;
参数下标越界 使用了从 0 开始的参数编号 检查参数下标是否从 1 开始
参数未设置 存在未绑定的占位符 检查 ? 的数量及参数绑定
主键重复 插入了已经存在的主键 检查表中的主键数据
SQL 执行异常 SQL 语法错误、字段不匹配或违反约束 查看 SQLException 的异常信息

9.JDBC 中的 Connection 接口

9.1 Connection 的基本概念

  • Connection 是 JDBC 提供的数据库连接接口,用于表示 Java 程序与数据库之间的连接,并提供创建 SQL 语句对象、管理事务等方法。
java 复制代码
// 获取数据库连接对象
Connection connection = dataSource.getConnection();
  • Connection:数据库连接接口。
  • connection:用于引用数据库连接对象的变量。
  • dataSource:数据源对象,保存数据库连接配置信息。
  • getConnection():获取数据库连接的方法。
  • 注意: Connection 是接口,不能直接使用 new Connection() 创建对象,通常通过 DataSource 获取其实现对象。

9.2 Connection 提供的主要方法

方法 作用
createStatement() 创建 Statement 对象,用于执行 SQL
prepareStatement(String sql) 创建 PreparedStatement 对象,用于预处理 SQL
prepareCall(String sql) 创建 CallableStatement 对象,用于调用存储过程
commit() 提交事务
rollback() 回滚事务
setAutoCommit(boolean) 设置是否自动提交事务
close() 关闭连接,释放相关资源

9.3 三种 SQL 语句对象

9.3.1 Statement
  • 创建普通 SQL 语句对象
  • 类实现了接口,由这个类实例化的对象就可以调用接口中的方法。
java 复制代码
// 创建普通 SQL 语句对象
Statement statement = connection.createStatement();

// 执行 SQL
int rows = statement.executeUpdate(  "INSERT INTO student VALUES (1, '张三')" );
  • 通过 createStatement() 创建。
  • 用于执行普通 SQL 语句。
  • 不提供 PreparedStatement 那样的参数绑定机制。
9.3.2 Connection 与其他 JDBC 对象的关系
java 复制代码
DataSource
    │
    │ getConnection()
    ▼
Connection接口
    │
    ├── createStatement():类中的方法
    │       └── Statement类实现了Connection接口
    │
    ├── prepareStatement(sql):类中的方法
           └── PreparedStatement类实现了Connection接口
    
9.3.3 核心知识点
  1. Connection 是 JDBC 中的数据库连接接口。
  2. Connection 提供 createStatement()、prepareStatement() 和 prepareCall() 等方法,用于创建不同的 SQL 语句对象。
  3. Connection 可以通过 commit()、rollback() 和 setAutoCommit() 管理事务。
  4. PreparedStatement 支持占位符和参数绑定,是常用的 SQL 执行方式。
  5. 数据库操作完成后,应及时关闭 PreparedStatement 和 Connection。

注意: DataSource 是数据源接口,MysqlDataSource 是 MySQL 驱动提供的实现类。由于接口中没有 setUrl()、setUser() 等方法,因此示例中需要将 DataSource 强制转换为 MysqlDataSource 才能调用这些方法。

10. JDBC 执行流程图

java 复制代码
创建并配置 DataSource
          ↓
获取 Connection
          ↓
构造 SQL 字符串
          ↓
调用 prepareStatement()
          ↓
使用 setXxx() 绑定参数
          ↓
调用 executeUpdate() / executeQuery()//将预处理后的sql语句执行
          ↓
获取执行结果
          ↓
关闭 PreparedStatement
          ↓
关闭 Connection
相关推荐
handonch1 小时前
MySQL → Kingbase PG模式 高频SQL替换清单
数据库·mysql·postgresql
姜鱼问生1 小时前
Kuma SQLite 备份坑
数据库·sqlite
用户69371750013841 小时前
当我说 Claude 搭配 GLM-5.3-Flash 太好用了,同事却提醒我:你可能正在失去对代码的掌控
android·后端·ios
水无痕simon1 小时前
15 MySQL是怎么保证高可用的?
数据库·mysql
漫步人生走在路上1 小时前
外贸SEO中的品牌词与产品词策略:大卖家和小卖家的不同打法
大数据·javascript·网络·数据库·人工智能·搜索引擎
张小姐的猫1 小时前
【MySQL】数据类型
android·linux·数据库·c++·mysql·adb·php
泡海椒1 小时前
JQuick-SQL LIMIT 分页:限制行数与偏移查询
数据库·sql
2501_916008891 小时前
马甲包过审卡在哪?Ipa Guard 能做的和做不到的
android·小程序·https·uni-app·iphone·webview
catino2 小时前
SQL调优
数据库·sql