MySQL终章(8)JDBC


目录

1.前言

2.正文

2.1JDBC概念

2.2三种编码方式

2.2.1第一种

2.2.2第二种(优化版)

2.2.3第三种(更优化版)

3.小结


1.前言

哈喽大家好吖,今天来给大家带来Java中的JDBC的讲解,之前学习的都是操作数据库的sql语言,那么我们如何通过程序来操作数据库呢?就是通过JDBC了,正文开始。

2.正文

2.1JDBC概念

JDBC是干什么的呢?

目的:使Java程序能够通过统一接口访问多种关系型数据库(如MySQL、Oracle、PostgreSQL等)。
核心思想:通过驱动(Driver)实现与具体数据库的解耦,开发者只需调用JDBC API,无需关心底层数据库差异。

访问数据库的常用流程:

  1. 确定数据库服务器的地址,端口号。(数据源)
  2. 建立连接,用户名,密码。(不同的数据库以哪种协议建立连接)(数据库连接)
  3. 发送要执行的SQL。(以什么样的形式发送,这里主要考虑编码的格式,即协议)(执行对象)
  4. 接收返回结果 (结果集,受影响的行数)  以哪种协议解析结果。 (结果集)
  5. 关闭连接。(释放资源,关闭连接)

JDBC是JAVA平台提供的接口,具体的实现是由数据库厂商去完成的。

2.2三种编码方式

在JDBC前记得先在maven中导入jar包:

Maven Repository: Search/Browse/Explorehttps://mvnrepository.com/pom文件是这样:

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.33</version>
</dependency>

测试的数据库代码我也在这里先提供给大家:

create database StudyRoom;
use StudyRoom;
-- 用户表
CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    phone VARCHAR(20) UNIQUE NOT NULL,
    email VARCHAR(100),
    school VARCHAR(100),
    points INT DEFAULT 0
);

INSERT INTO users values(01,'tom','12345','123456789','@123456789','HEDU',10)

正式开始: 

2.2.1第一种

代码:

import java.sql.*;
import java.text.MessageFormat;
import java.util.Scanner;

public class jdbc1 {
    public static void main(String[] args) {

        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            // 1. 加载数据库厂商提供的驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 获取数据库连接
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/studyroom?characterEncoding=utf8" +
                    "&allowPublicKeyRetrieval=true&useSSL=false", "root", "123456");
            // 3. 创建Statement对象
            statement = connection.createStatement();
            // 4. 定义SQL并执行SQL语句
            System.out.println("请输入学生编号:");
            Scanner scanner = new Scanner(System.in);
            // 接收用户的输入
            int id = scanner.nextInt();
            String sql = "select user_id, username, password, phone, email, school, points from users where user_id = '" + id + "'";
            // 5. 执行SQL,获取查询结果
            resultSet = statement.executeQuery(sql);
            // 6. 对结果集进行遍历,获取数据
            // 如果一下条有记录,返回true,没有则返回false
            while (resultSet.next()) {
                // 获取学生Id
                long user_id = resultSet.getLong(1);
                String username = resultSet.getString(2);
                String password = resultSet.getString(3);
                String phone = resultSet.getString(4);
                String email = resultSet.getString(5);
                String school = resultSet.getString(6);
                long points= resultSet.getLong(7);
                System.out.println(MessageFormat.format("学生编号={0}, 姓名={1}, 密码={2}, 手机号={3}, 邮箱={4}, 学校={5}, 点数={6}", user_id, username, password, phone
                        , email, school, points));
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 依次释放资源,关闭连接
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

核心思路讲解:

1.加载数据库驱动

  • 使用 Class.forName("com.mysql.cj.jdbc.Driver") 加载 MySQL 数据库的 JDBC 驱动类,这是建立与 MySQL 数据库连接的必要步骤,让 Java 程序能够识别并使用 MySQL 的驱动来与数据库进行通信。

2.获取数据库连接

  • 通过 DriverManager.getConnection 方法,使用数据库的 URL(包括数据库的地址、端口、数据库名以及一些连接参数,如字符编码、是否允许公钥检索、是否使用 SSL 等)、用户名和密码来获取与数据库的连接,将返回的连接赋值给 connection 对象。

3.创建 Statement 对象

  • 调用 connection 对象的 createStatement 方法创建一个 Statement 对象,这个对象用于向数据库发送 SQL 语句并执行。

4.定义 SQL 查询语句并执行

  • 提示用户输入学生编号,并通过 Scanner 对象接收用户的输入。

  • 根据用户输入的学生编号构建 SQL 查询语句,查询 users 表中对应学生编号的相关信息,包括 user_id、username、password、phone、email、school、points 等字段。

  • 使用 statement 对象的 executeQuery 方法执行构建好的 SQL 查询语句,将查询结果存储在 resultSet 对象中。

5.处理查询结果

  • 使用 while 循环和 resultSet 对象的 next 方法遍历查询结果集,每次调用 next 方法都会将结果集中的指针向下移动一行,如果还有数据则返回 true,否则返回 false。

  • 在循环体内,使用 resultSet 对象的 get 系列方法(如 getLonggetString 等)根据字段的顺序或列名获取每一行数据中的各个字段值。

  • 使用 MessageFormat.format 方法将获取到的字段值按照指定的格式(包含占位符)组合成一个字符串,并输出到控制台,显示学生的所有相关信息。

6.关闭资源

  • 在 finally 块中,依次判断 resultSet、statement、connection 对象是否不为 null,如果不为 null,则分别调用它们的 close 方法关闭这些资源,释放数据库连接和相关资源,这是非常重要的一步,避免了资源泄漏的问题。即使在执行过程中出现异常,finally 块中的代码也会被执行,确保资源被正确关闭。

2.2.2第二种(优化版)

代码:

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.*;
import java.text.MessageFormat;
import java.util.Scanner;

public class jdbc2 {
    public static void main(String[] args) {
        // 定义MySQL数据源对象
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        // 设置数据库连接串
        mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/studyroom?characterEncoding=utf8" +
                "&allowPublicKeyRetrieval=true&useSSL=false");
        // 用户名
        mysqlDataSource.setUser("root");
        // 密码
        mysqlDataSource.setPassword("123456");

        // 定义JDBC的数据源对象
        DataSource dataSource = mysqlDataSource;

        // 定义连接对象
        Connection connection = null;
        // 定义预处理SQL执行对象
        PreparedStatement statement = null;
        // 定义结果集对象
        ResultSet resultSet = null;

        try {
            // 1. 通过数据源获取数据库连接
            connection = dataSource.getConnection();
            // 2. 获取预处理SQL执行对象
            //输入
            System.out.println("请输入学生编号:");
            Scanner scanner = new Scanner(System.in);
            int id = scanner.nextInt();
            // 定义要执行的SQL
            String sql = "select user_id, username, password, phone, email, school, points from users where user_id = ?";
            statement = connection.prepareStatement(sql);
            // 3. 用真实值替换占位符
            statement.setInt(1, id);
            // 4. 执行SQL,获取结果集
            resultSet = statement.executeQuery();
            // 5. 遍历结果集
            while (resultSet.next()) {
                // 获取学生Id
                long user_id = resultSet.getLong(1);
                String username = resultSet.getString(2);
                String password = resultSet.getString(3);
                String phone = resultSet.getString(4);
                String email = resultSet.getString(5);
                String school = resultSet.getString(6);
                long points= resultSet.getLong(7);
                System.out.println(MessageFormat.format("学生编号={0}, 姓名={1}, 密码={2}, 手机号={3}, 邮箱={4}, 学校={5}, 点数={6}", user_id, username, password, phone
                        , email, school, points));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 依次释放资源,关闭连接
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

核心思路讲解:

1.配置数据库连接信息

  • 创建 MysqlDataSource 对象,通过设置其 URL、用户名和密码来配置数据库连接信息,这种方式将连接信息集中管理,使得代码更加清晰和易于维护,方便后续对连接信息的修改。

2.获取数据库连接

  • 将配置好的 MysqlDataSource 对象赋值给 DataSource 类型的变量 dataSource,然后通过 dataSource 的 getConnection 方法获取数据库连接,这与直接使用 DriverManager 获取连接相比,更符合 JDBC 的最佳实践,便于后续进行连接池等高级功能的集成。

3.使用 PreparedStatement 执行 SQL 语句

  • 定义 SQL 语句时使用了占位符 "?",然后通过 connection.prepareStatement(sql) 获取 PreparedStatement 对象,这种方式可以有效防止 SQL 注入攻击,因为 PreparedStatement 会对参数进行预编译和转义处理。

  • 使用 statement.setInt(1, id) 将用户输入的学生编号设置到 SQL 语句的占位符位置,将参数与 SQL 语句分离,提高了代码的安全性和可读性。

4.执行查询和处理结果

  • 调用 statement.executeQuery() 执行查询操作,获取结果集。

  • 遍历结果集的方式与之前的代码类似,通过 resultSet.next() 移动指针并获取数据,然后使用 MessageFormat.format 方法输出格式化后的学生信息。

5.关闭资源

  • 在 finally 块中关闭资源的逻辑与之前代码相同,确保无论是否出现异常,都会关闭 resultSet、statement 和 connection 对象,释放数据库资源。


相比第一种有哪些优化呢?

  • 数据库连接管理 :之前的代码直接通过 DriverManager.getConnection 获取连接,而本代码使用了 MysqlDataSource 数据源来配置和获取连接,这种方式更灵活,便于后续进行连接池等优化,提高了代码的可维护性和可扩展性。

  • SQL 注入防护 :之前的代码通过字符串拼接构建 SQL 语句,容易受到 SQL 注入攻击,而本代码使用了 PreparedStatement 和参数占位符的方式,有效防止了 SQL 注入问题,增强了程序的安全性。

  • 代码可读性和可维护性 :通过将数据库连接信息集中配置在数据源中,以及使用 PreparedStatement 的参数设置方式,使得代码结构更加清晰,便于理解和后续的维护。

2.2.3第三种(更优化版)

我们发现,如果每一次尝试通过程序来操作数据库都要一次一次建立连接,代码会非常麻烦,于是我们引入连接池的概念,将连接数据库与释放资源的操作封装起来,这样就会非常方便。

代码结构:

DButil:

package utils;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class DButil {

    private static DataSource dataSource = null;

    private static final String URL = "jdbc:mysql://127.0.0.1:3306/studyroom?characterEncoding=utf8" +
            "&allowPublicKeyRetrieval=true&useSSL=false";

    private static final String USER = "root";

    private static final String PASSWORD = "123456";

    static {
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        mysqlDataSource.setURL(URL);
        mysqlDataSource.setUser(USER);
        mysqlDataSource.setPassword(PASSWORD);
        dataSource = mysqlDataSource;
    }

    private DButil(){}

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void close(ResultSet resultSet, Statement statement,Connection connection){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}

JDBC3:

package com.example.demo;

import utils.DButil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.Scanner;

public class jdbc3 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement statement = null;

        try {
            connection = DButil.getConnection();

            String sql = "select user_id, username, password, phone, email, school, points from users where user_id = ?";

            statement = connection.prepareStatement(sql);

            Scanner scanner = new Scanner(System.in);
            int id = scanner.nextInt();

            statement.setInt(1,id);

            ResultSet resultSet = statement.executeQuery();

            while (resultSet.next()) {
                // 获取学生Id
                long user_id = resultSet.getLong(1);
                String username = resultSet.getString(2);
                String password = resultSet.getString(3);
                String phone = resultSet.getString(4);
                String email = resultSet.getString(5);
                String school = resultSet.getString(6);
                long points= resultSet.getLong(7);
                System.out.println(MessageFormat.format("学生编号={0}, 姓名={1}, 密码={2}, 手机号={3}, 邮箱={4}, 学校={5}, 点数={6}", user_id, username, password, phone
                        , email, school, points));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DButil.close(null,statement,connection);
        }

    }
}

代码核心思路:

DButil 类(工具类)

  • 功能

    • 专门用于管理数据库连接和资源关闭的工具类,将数据库连接的获取和资源关闭的逻辑抽取出来,方便在多个地方复用,避免重复代码,提高代码的可维护性和复用性。

  • 静态代码块初始化数据源

    • 在类加载时,通过静态代码块创建并配置 MysqlDataSource 对象,设置数据库的 URL、用户名和密码,并将其赋值给 dataSource 对象。这种方式确保数据源只初始化一次,提高了效率。

  • 私有构造方法

    • 将构造方法私有化,防止外部创建该工具类的实例,因为工具类主要用于提供静态方法,不需要实例化。

  • 获取数据库连接

    • 提供 getConnection 静态方法,通过调用 dataSource.getConnection() 向外提供数据库连接对象,方便其他类使用。

  • 关闭资源

    • 提供 close 静态方法,接收 ResultSetStatementConnection 对象作为参数,并依次判断它们是否不为 null,若不为 null 则关闭它们,释放资源。这样统一管理资源关闭逻辑,避免资源泄漏。


jdbc3 类(主程序类):

  • 功能

    • 使用 DButil 工具类获取数据库连接,并通过 PreparedStatement 执行 SQL 查询语句,根据用户输入的学生编号查询学生信息并输出。

  • 获取数据库连接

    • 调用 DButil.getConnection() 方法获取数据库连接,而不是像之前的代码直接在主程序中配置连接信息和创建连接,这样使得数据库连接的获取更加规范和集中管理。

  • 执行 SQL 查询

    • 定义 SQL 语句时继续使用占位符 "?",并通过 connection.prepareStatement(sql) 获取 PreparedStatement 对象,然后使用 statement.setInt(1, id) 设置参数值,有效防止 SQL 注入,同时提高代码的可读性和安全性。

  • 处理查询结果和关闭资源

    • 执行查询获取结果集后,遍历结果集并输出学生信息,这部分逻辑与之前的代码类似。

    • 在 finally 块中调用 DButil.close 方法关闭资源,而不是像之前在主程序中手动关闭,简化了资源关闭的代码,减少了出错的可能性。


优化点:

  • 代码复用和单一职责 :将数据库连接的获取和资源关闭的逻辑抽取到专门的 DButil 工具类中,遵循单一职责原则,使每个类的职责更加明确,提高了代码的复用性。在之前的代码中,这些逻辑都分散在主程序中,导致代码重复且不易维护。

  • 资源管理更规范 :通过工具类统一管理资源关闭,确保在任何情况下(即使出现异常)都能正确关闭资源,避免资源泄漏的问题。之前的代码虽然也有在 finally 块中关闭资源,但随着项目规模的扩大和复杂性的增加,这种方式容易出现遗漏或错误。

  • 提高可维护性和可扩展性 :如果将来需要更改数据库连接信息或切换数据库类型,只需修改 DButil 类中的相关配置即可,而无需修改每个使用数据库连接的地方,大大提高了代码的可维护性和可扩展性。

运行截图:

 

3.小结

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃烤鸡翅的酸菜鱼

希望大家对我多多支持喔~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值