10.1 第一个JDBC程序

系列 - JAVA JDBC

JDBC的全称是Java数据库连接(Java Database Connectivity),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句完成对数据库中数据的操作。

mysql-connector-java-8.0.11.jar

1、创建项目后,在项目目录中新建文件夹,名为lib

2、将 jdbc 驱动文件放到该文件夹下,如下图所示:

3、右键点击 lib 目录,选择 Add as Library

在数据库中创建数据库、表并生成实验数据:

sql

-- 创建数据库(如果需要)
CREATE DATABASE IF NOT EXISTS school;

-- 使用数据库
USE school;

-- 创建学生表
CREATE TABLE student (
    id INT PRIMARY KEY AUTO_INCREMENT,  -- 学号,自增主键
    name VARCHAR(20) NOT NULL,          -- 姓名,不能为空
    age INT,                            -- 年龄
    gender CHAR(1),                     -- 性别(M/F)
    class VARCHAR(20),                  -- 班级
    score DECIMAL(5,2)                  -- 成绩,支持两位小数
);

-- 插入示例数据
INSERT INTO student (name, age, gender, class, score) VALUES
    ('张三', 18, 'M', '计算机1班', 85.5),
    ('李四', 19, 'M', '计算机1班', 92.0),
    ('王五', 18, 'M', '计算机2班', 78.5),
    ('赵六', 19, 'F', '计算机2班', 95.5),
    ('小红', 18, 'F', '计算机1班', 90.0),
    ('小明', 20, 'M', '计算机2班', 88.0);

-- 查看表结构
DESC student;

-- 查看数据
SELECT * FROM student;

应用程序使用JDBC访问数据库的方式如下图。

graph TD;
    A[应用程序] <--> B[JDBC]
    B <--> C[MySQL驱动]
    B <--> D[Oracle驱动]
    C <--> E[(MySQL)]
    D <--> F[(Oracle)]

  1. 应用程序层
    • 我们编写的Java程序
    • 通过JDBC API发起数据库操作请求
  2. JDBC层
    • Java提供的标准数据库接口
    • 定义了一套访问数据库的标准规范
    • 好比一个"翻译官",负责Java程序和各种数据库之间的通信
  3. 数据库驱动层
    • 由各数据库厂商提供
    • MySQL驱动:mysql-connector-java.jar
    • Oracle驱动:ojdbc.jar
    • 实现JDBC接口,负责与具体数据库通信
  4. 数据库层
    • 实际的数据库服务器
    • 可以是MySQL、Oracle等任意数据库
为什么需要这样的架构
  1. 统一标准:Java程序只需要学习JDBC接口,就能操作任何数据库
  2. 解耦合:更换数据库时,只需要更换驱动程序,应用代码无需修改
  3. 跨平台:不同操作系统都可以使用相同的代码访问数据库

使用JDBC的常用API实现JDBC程序的步骤如下图:

  1. DriverManager(驱动管理)
    • 加载数据库驱动
    • 相当于安装数据库的"驱动程序"
  2. Connection(连接)
    • 建立与数据库的连接
    • 类似于登录数据库
  3. Statement(语句)
    • 创建SQL语句对象
    • 用来执行SQL命令
    • 可以理解为准备要发送给数据库的指令
  4. ResultSet(结果集)
    • 保存查询结果的对象
    • 类似于表格,包含了查询返回的所有数据
    • 可以一行一行地读取数据

第一步是加载数据库驱动,因为它是Java程序连接数据库的桥梁。

加载操作可以通过java.lang.Class类的静态方法forName(String  className)实现,具体示例如下所示:

java

Class.forName("DriverName");  // 常用

DriverName表示数据库的驱动类。以MySQL数据库为例,MySQL驱动类在6.0.2版本之前为com.mysql.jdbc.Driver,而在6.0.2版本之后为com.mysql.cj.jdbc.Driver,我们要根据自己数据库版本选择对应的驱动类。

java

try {  
    Class.forName("com.mysql.cj.jdbc.Driver");  
} catch (ClassNotFoundException e) {  
    e.printStackTrace();  
}

DriverManager 接口用于加载JDBC驱动、创建与数据库的连接。在DriverManager接口中,定义了两个比较重要的静态方法:

方法名称 功能描述
static void registerDriver(Driver driver) 注册给定的JDBC驱动程序
🔴static Connection getConnection(String url, String user, String pwd) 建立和数据库的连接,并返回表示连接的Connection对象

其中 Connection 类型是一个接口类型,获取数据库连接的具体方式如下:

java

Connection conn = DriverManager.getConnection(String url, String user, String pwd); 

从上述代码可以看出,getConnection()方法有3个参数,分别表示连接数据库的地址、登录数据库的用户名和密码。

以MySQL数据库为例,MySQL数据库地址(URL)的书写格式如下:

text

jdbc:mysql://主机名或IP:端口号/数据库名

继续完善我们的代码:

java

// 1. 加载驱动  
Class.forName("com.mysql.cj.jdbc.Driver");  
  
// 2. 连接数据库  
String url = "jdbc:mysql://localhost:3306/school?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC";  
String username = "root";  
String password = "root";  

Connection connection = DriverManager.getConnection(url, username, password);
注意
  1. 使用Connection需要导入包java.sql.Connection
  2. 使用 DriverManager 需要导入包 java.sql.DriverManager

通过Connection对象获取Statement对象

Connection创建Statement对象的方法有以下3个:

  1. createStatement():创建基本的Statement对象
  2. prepareStatement():创建PreparedStatement对象
  3. prepareCall():创建CallableStatement对象

以创建基本的Statement对象为例,创建方式如下:

java

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

使用Statement执行SQL语句,所有的Statement都有以下3种执行SQL语句的方法:

  1. execute():可以执行任何SQL语句
  2. executeQuery():通常执行查询语句,执行后返回代表结果集的ResultSet对象
  3. executeUpdate():主要用于执行DML和DDL语句。执行DML语句,如INSERT、UPDATE或DELETE时,返回受SQL语句影响的行数;执行DDL语句返回0。
注释
  1. DML (Data Manipulation Language 数据操作语言):主要用于操作数据库中的数据
  2. DDL (Data Definition Language 数据定义语言):主要用于操作数据库对象(如表、视图、索引等)

如果执行的SQL语句是查询语句,执行结果将返回一个ResultSet对象,该对象保存了SQL语句查询的结果。程序可以通过操作该ResultSet对象取出查询结果。

每次操作数据库结束后都要关闭数据库连接,释放资源,关闭顺序和声明顺序相反。需要关闭的资源包括ResultSet、Statement和Connection等。

在 finally 代码块中关闭 ResultSet、Statement和Connection

或者,使用更简洁的 try-with-resources 语法:

java

import java.sql.Connection;  
import java.sql.ResultSet;  
import java.sql.Statement;  
import java.sql.DriverManager;  
  
public class Example02 {  
    public static void main(String[] args) {  
        try {  
            // 1. 加载驱动  
            Class.forName("com.mysql.cj.jdbc.Driver");  
  
            // 2. 准备连接参数  
            String url = "jdbc:mysql://localhost:3306/school?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC";  
            String username = "root";  
            String password = "root";  
  
            // 使用try-with-resources自动关闭资源  
            try (  
                    // 创建连接  
                    Connection connection = DriverManager.getConnection(url, username, password);  
                    // 创建语句对象  
                    Statement statement = connection.createStatement();  
                    // 执行查询获取结果集  
                    ResultSet resultSet = statement.executeQuery("select * from student")  
            ) {  
                // 处理结果集  
                while (resultSet.next()) {  
                    int id = resultSet.getInt("id");  
                    String name = resultSet.getString("name");  
                    int age = resultSet.getInt("age");  
                    String gender = resultSet.getString("gender");  
                    String className = resultSet.getString("class");  
  
                    System.out.println("id=" + id + ", name=" + name + ", age=" + age +  
                            ", gender=" + gender + ", className=" + className);  
                }  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

向数据库写入数据主要使用 INSERT 语句,基本步骤与查询数据类似,但有以下几点不同:

  1. 执行SQL语句时使用 executeUpdate() 方法而不是 executeQuery()
  2. 不需要处理 ResultSet,而是获取受影响的行数
  3. 通常需要处理事务(commit/rollback)

java

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

public class Example03 {
    public static void main(String[] args) {
        try {
            // 1. 加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2. 准备连接参数
            String url = "jdbc:mysql://localhost:3306/school?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC";
            String username = "root";
            String password = "root";

            // 使用try-with-resources自动关闭资源
            try (
                Connection connection = DriverManager.getConnection(url, username, password);
                Statement statement = connection.createStatement()
            ) {
                // 准备INSERT语句
                String sql = "INSERT INTO student (name, age, gender, class, score) " +
                           "VALUES ('小张', 19, 'M', '计算机1班', 88.5)";
                
                // 执行INSERT语句
                int rows = statement.executeUpdate(sql);
                
                // 输出受影响的行数
                System.out.println("成功插入 " + rows + " 条数据");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果:

在 Navicat 中验证是否有新数据:

写入数据的注意事项
  1. 使用 executeUpdate() 方法执行INSERT语句
  2. 该方法返回受影响的行数
  3. 如果写入失败会抛出异常
  4. 注意字符串类型的值需要用单引号括起来

相关内容