初始MYSQL数据库(8)—— JDBC编程

news2024/9/30 8:58:15

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页:我要学编程(ಥ_ಥ)-CSDN博客

所属专栏: MYSQL

目录

JDBC的概念 

JDBC的使用

加载驱动包

建立连接

创建 statement 对象

定义并执行SQL语句 

处理结果集

关闭资源 

SQL注入

优化后的JDBC

JDBC编程的两种方式对比


前面,我们学习了MySQL数据库中SQL语句的基础语法并且在命令行上面也进行了一些实际的操作。现在我们就来学习使用IDEA去编写SQL语句来操作数据库。

JDBC的概念 

JDBC(Java DataBase Connectivity,Java数据库连接)是Java程序和数据库之间的桥梁,包含
了一套Java定义的用于执行SQL语句的接口,使开发者能够编写数据库的程序。JDBC的主要作用是:与数据库建立连接、发送SQL语句和处理数据库执行结果。关系示意图:

从上面我们知道了,JDBC其实就是一套Java源生的。而其的实现也与我们无关,是由数据库厂商自己提供的。我们只需要去使用即可。

接下来我们就来使用JDBC去操作数据库。

JDBC的使用

JDBC的使用可以大致概括为以下几个方面:

1、加载数据库厂商提供的驱动包。即实现了JDBC的接口

2、建立数据库连接

3、创建statement对象

4、编写SQL语句,并通过statement对象去执行SQL语句

5、接收结果集或者返回值

6、关闭资源

加载驱动包

加载驱动包的过程可以简单理解为在手机上安装一个软件的过程。 而安装软件的过程如下所示:

1、打开应用商店;

2、去应用商店里面找到该软件;

3、下载该软件。

4、安装该软件,在运行即可。

同理加载驱动包也是三个步骤:

1、打开Maven官网(驱动包全部在里面);

Maven官网,点我

2、找到与自己电脑中数据库版本相对应数据库;

那问题来了,怎么判断自己是哪个版本呢?

按 win + R 打开命令行,然后输入 mysql -uroot -p,接着摁下回车键,再输入密码,成功打开MySQL之后,就输入 select version(); 去查询此时正在运行的MySQL的版本是多少。

如果你和我一样是MySQL8.0.39的话,那么就是去第一个结果中找到MySQL8.3即可。

3、在该目录下,来到Maven所在目录,点击框内英文即可。 

 4、将复制的内容粘贴到Maven工程中。

这里首先得创建一个Maven工程。

然后只需要套个框架,在框架内粘贴我们复制的内容即可。 

 接下来就是正式的加载驱动包了,正如运行程序。

现在就已经将驱动包加载完成啦!下面就是要建立连接了。

建立连接

// 2. 获取数据库连接
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/java?characterEncoding=utf8" +
                    "&allowPublicKeyRetrieval=true&useSSL=false", "root", "123456");;

这里是固定写法:

即修改 3306/ 后面的值,即对应的数据库。root 就是用户名,123456 就是mysql的密码。 

创建 statement 对象

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

定义并执行SQL语句 

// 4. 定义SQL并执行SQL语句
System.out.print("请输入学生姓名:");
Scanner scanner = new Scanner(System.in);
// 接收用户的输入
String name = scanner.next();
// 把查询的列详细写出来
String sql = "select id, name, age, gender from student where name = '" + name + "'";
// 5. 执行SQL,获取查询结果
resultSet = statement.executeQuery(sql);

处理结果集

// 6. 对结果集进行遍历,获取数据
// 如果一下条有记录,返回true,没有则返回false
while (resultSet.next()) {
    // 获取学生的信息
    long stuId = resultSet.getLong(1); // 这里的1是指第一列
    String stuName = resultSet.getString(2);
    int stuAge = resultSet.getInt(3);
    byte stuGender = resultSet.getByte(4);
    System.out.println(MessageFormat.format("学生编号={0}, 学生姓名={1}, 学生年龄={2}, 
        学生性别={3}",stuId, stuName, stuAge, stuGender));
}

关闭资源 

// 依次释放资源,关闭连接
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();
    }
}

下面是综合的代码(包括捕获异常):

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

public class JDBC_Demo1 {
    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/java?characterEncoding=utf8" +
                    "&allowPublicKeyRetrieval=true&useSSL=false", "root", "123456");
            // 3. 创建Statement对象
            statement = connection.createStatement();
            // 4. 定义SQL并执行SQL语句
            System.out.print("请输入学生姓名:");
            Scanner scanner = new Scanner(System.in);
            // 接收用户的输入
            String name = scanner.next();
            String sql = "select id, name, age, gender from student where name = '" + name + "'";
            // 5. 执行SQL,获取查询结果
            resultSet = statement.executeQuery(sql);
            // 6. 对结果集进行遍历,获取数据
            // 如果一下条有记录,返回true,没有则返回false
            while (resultSet.next()) {
                // 获取学生的信息
                long stuId = resultSet.getLong(1);
                String stuName = resultSet.getString(2);
                int stuAge = resultSet.getInt(3);
                byte stuGender = resultSet.getByte(4);
                System.out.println(MessageFormat.format("学生编号={0}, 学生姓名={1}, 学生年龄={2}, 学生性别={3}",
                        stuId, stuName, stuAge, stuGender));
            }

        } 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();
                }
            }
        }
    }
}

注意:try块 中定义的变量,其作用域只是在try块中,只有在全局的变量,才能在try-catch 中使用,并且在finally块中也是可以使用。(全局只是相对try-catch和finally而言的)

效果演示:

JDBC:

命令行:

上面这种方法虽然的确可以操作数据库,但是从性能来讲,还是比较差的。因为DriverManager每次调用getConnection方法都会初始化一个新的连接,使用完成后会关闭真实连接,导致资源浪费。因此 DataSource就闪亮登场了。DataSource使用了连接池的技术,会在初始化时创建一定数量的数据库连接,这些连接可以重复使用,关闭时并不是真正关闭连接,而是将连接归还给连接池,以供后续使用,有效地提高资源利用率和和性能。

SQL注入

Statement 用于执行静态SQL语句并返回执行结果,由于只能执行静态语句,所以这里会有一个问题,假设一个语句中需要动态的参数,比如where子句中的条件,那么只能通过字符串拼接的方式组装完成的SQL语句。就和我们上面写的一样,但如果此时有人写了一个必然成立的代码呢?

JDBC进行的检查就是将输入的SQL语句中的所有空格给去掉,从而进行语法检查。 

 上面这种情况叫做 SQL注入。

字符串拼接形式构造SQL语句时,如果不处理参数中的特殊字符就会造成SQL注入,这是一个非常
严重的安全性问题。别人可以通过这种手段把数据内容全部盗取,从而对公司、个人造成损失。

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应
用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

既然出现了这么严重的问题,肯定是需要解决的,因此便有了和编译代码的过程一样,进行预编译。在预编译阶段处理SQL注入的问题。

预编译SQL语句对象,SQL语句被预编译并存储在PreparedStatement对象中,可以使用该对象多次执行SQL语句,同时可以解决SQL注入问题。

优化后的JDBC

现在我们来写优化后的代码:

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
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 JDBC_Demo2 {
    public static void main(String[] args) {
        // 定义mysql数据源对象
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        // 设置数据连接串
        // url
        mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java?characterEncoding=utf8" +
                "&allowPublicKeyRetrieval=true&useSSL=false");
        // 用户名
        mysqlDataSource.setUser("root");
        // 密码
        mysqlDataSource.setPassword("123456");


        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        // 上面是厂商给我们提供的实现类,我们要使用Java层面的数据源接口
        DataSource dataSource = mysqlDataSource; // 向上转型
        try {
            // 从数据源中获取连接
            connection = dataSource.getConnection();
            // 定义执行的SQL
            String sql = "select id, name, age, gender from student where name = ?"; // 使用占位符
            // 对SQL语句进行预编译
            preparedStatement = connection.prepareStatement(sql);
            // 接收输入数据
            System.out.print("请输入学生姓名:");
            Scanner scanner = new Scanner(System.in);
            String name = scanner.next();
            // 用真实数据代替占位符
            preparedStatement.setString(1,name);
            // 执行SQL语句并接收结果集
            resultSet = preparedStatement.executeQuery(); // 这里不要传入SQL了
            while (resultSet.next()) {
                long stuId = resultSet.getLong(1);
                String stuName = resultSet.getString(2);
                int stuAge = resultSet.getInt(3);
                byte stuGender = resultSet.getByte(4);
                System.out.println(MessageFormat.format("学生编号{0},学生姓名{1}, 学生年龄{2}, 学生性别{3}"
                        ,stuId, stuName, stuAge, stuGender));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

上面的代码主要有两个优化的地方:

1、获取数据库连接不再是单独申请,而是在数据源中进行索取。

由于JDBC只是一组接口,因此我们没有办法直接创建数据源对象,只能通过mysql厂商提供的数据源对象来进行向上转型。而前面的获取数据连接时,是每一次都需要写入URL等数据,而数据源只需要获取一次即可,因此我们就是直接通过mysql提供的数据源对象进行设置URL等数据。

2、在优化数据源的基础上,我们还需要对SQL语句进行预编译。因此得先写一个SQL语句,并且不能再是拼接字符串的方式了,所以这里就用到了占位符。然后再让我们自己输入数据去填充占位符,接着就可以直接进行查询了。 

上面我们写的代码都是查询操作,现在我们来写一个简单的新增操作。

大体操作是一致的。

import com.mysql.cj.jdbc.CallableStatement;
import com.mysql.cj.jdbc.MysqlDataSource;

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

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

        // 上面是厂商给我们提供的实现类,我们要使用Java层面的数据源接口
        DataSource dataSource = mysqlDataSource;
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            // 建立连接
            connection = dataSource.getConnection();
            // 定义SQL并进行预编译
            String sql = "insert into student values (?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            // 接收输入
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入新增学生编号:");
            long id = Long.parseLong(scanner.next()); // 不会出现问题
            System.out.print("请输入新增学生姓名:");
            String name = scanner.next();
            System.out.print("请输入新增学生年龄:");
            int age = Integer.parseInt(scanner.next());
            System.out.print("请输入新增学生性别:");
            byte gender = Byte.parseByte(scanner.next());
            // 替换占位符
            preparedStatement.setLong(1,id); // 默认从1开始的
            preparedStatement.setString(2, name);
            preparedStatement.setInt(3,age);
            preparedStatement.setByte(4,gender);
            // 执行SQL语句,并接收结果集
            int line = preparedStatement.executeUpdate(); // 这里返回的是受影响的行数
            if (line == 1) {
                System.out.println("新增成功!");
            } else {
                System.out.println("新增失败!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 依次关闭资源
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

效果演示:

注意:

1、这里之所以全部改用next 方法,是因为其他的方法可能会出现一些预料不到的问题。

2、占位符可以有多个,是从1按照顺序开始的。

JDBC编程的两种方式对比

现在我们就来总结一下JDBC的简单使用过程。

第一种方式(不推荐使用):

1、加载数据库厂商提供的驱动包。注意:一个项目中只需加载一次,就类似于一个手机上面只能安装一个同样的应用程序(虚拟机除外)。

2、建立连接。

3、创建Statement对象

4、通过Statement对象执行SQL语句

5、处理结果集

6、关闭资源。

第二种方式(推荐使用):

1、 创建数据源对象。

        (a):使用数据库厂商提供的数据源,创建对象,设置连接串。

        (b):用Java提供的接口去接收,进行向上转型。

2、建立连接。

3、定义SQL语句,进行预编译。

4、接收真实数据,代替占位符。

5、执行SQL语语,并接收返回值。

6、关闭资源。

第二种方式的优点:

1、主要是针对SQL注入的情况,进行了预编译优化。

2、对于第一种方式频繁的建立连接,关闭资源做了优化:定义一个数据源,每次建立连接都是通其中的某一个建立连接,并且当使用完成之后,也不会真的把资源关闭,而是还给了数据源。

好啦!本期 初始MYSQL数据库(8)—— JDBC编程 的学习之旅就到此结束啦!我们下一期再一起学习吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2179226.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

taobao.item_get_appAPI接口原app数据测试指南

在电商竞争日益激烈的当下,数据成为了商家们争夺市场的重要武器。淘宝,作为中国最大的在线零售平台,其庞大的商品库和用户群体为商家提供了巨大的商机。为了帮助商家更好地了解市场动态,优化库存和营销策略,淘宝推出了…

详细分析CollUtil的基本知识(附Demo)

目录 前言1. 集合交并差2. CRUD3. 常用 前言 java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)【Java项目】实战CRUD的功能整理(持续更新) CollUtil 是一个工具类,通常用于集合的操作,提供…

用友U8+CRM leadconversion.php SQL注入复现

0x01 产品描述: 用友U8-CRM是企业利用信息技术,是一项商业策略,它通过依据市场细分组织企业资源、培养以客户为中心的经营行为、执行以客户为中心的业务流程等手段来优化企业的客户满意度和获利能力。 0x02 漏洞描述: 用友 U8 CR…

<<迷雾>第5章 从逻辑学到逻辑电路(1)--继电器 示例电路

布尔代数可以用来解释复杂的开关电路 info::操作说明 鼠标单击开关切换开合状态 注: 开关不能全部都合上, 否则会导致模拟器异常 该异常与模拟器把开关和导线当作了零电阻的理想部件有关, 为避免此问题, 可在开关形成的回路上添加一个额外的电阻 另: 异常出现后, 右上方的运行按…

Nagle 算法:优化 TCP 网络中小数据包的传输

1. 前言 在网络通信中,TCP(传输控制协议)是最常用的协议之一,广泛应用于各种网络应用,如网页浏览、文件传输和在线游戏等。然而,随着互联网的普及,小数据包的频繁传输成为一个不容忽视的问题。…

行为设计模式 -策略设计模式- JAVA

策略设计模式 一 .简介二. 案例2.1 抽象策略(Strategy)类2.2 具体策略(Concrete Strategy)类2.3 环境(Context)类2.4 测试 三. 结论3.1 优缺点3.2 使用场景 前言 这是我在这个网站整理的笔记,有错误的地方请…

Git大框架总结

下面首先是我对于git的一个小总结,主要是大框架 首先是四区,因为大部分你所有的工作都是在这四个区里的实现的,包括要提交一个东西,是先是在工作区修改,后用add添加到暂存区,后提交到本地仓库,当…

文献阅读——电力系统安全域边界通用搜索模型与近似方法

文章标题 DOI:10.13334/j.0258-8013.pcsee.190884 ©2020 Chin.Soc.for Elec.Eng. 4411 文章编号:0258-8013 (2020) 14-4411-19 中图分类号:TM 74 电力系统安全域边界通用搜索模型与近似方法 姜涛,李晓辉,李雪*&a…

十五、存储过程与函数

文章目录 0. 引用1. 存储过程概述1.1 理解1.2 分类 2. 创建存储过程2.1 语法分析 3. 调用存储过程3.1 调用格式3.2 代码举例3.3 如何调试 4. 存储函数的使用4.1 语法分析4.2 调用存储函数4.3 代码举例4.4 对比存储函数和存储过程 5. 存储过程和函数的查看、修改、删除5.1 查看5…

建筑物变化检测算法baseline工程,开箱即用,23年5月测试准确度超越阿里云aiearth

建筑物变化检测算法baseline工程,开箱即用,23年5月测试准确度超越阿里云aiearth 建筑物变化检测算法Baseline工程 项目背景 随着城市化进程的加快,对建筑物的变化进行监测变得尤为重要。这不仅有助于城市管理与规划,还能够为灾害…

LeetCode 热题 100 回顾6

干货分享,感谢您的阅读!原文见:LeetCode 热题 100 回顾_力code热题100-CSDN博客 一、哈希部分 1.两数之和 (简单) 题目描述 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标…

Kubernetes高级功能

资源配额 什么是资源配额 资源配额,通过 ResourceQuota 对象来定义,对每个命名空间的资源消耗总量提供限制。 它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命名空间中的 Pod 可以使用的计算资源的总上限。 资源配额应用 创建的…

C语言中的日志机制:打造全面强大的日志系统

前言 在软件开发中,良好的日志记录机制对于调试、监控程序状态和维护系统的稳定性至关重要。本文将介绍如何在C语言中构建一个全面强大的日志系统,并提供一些示例代码。 1. 日志的基本概念 日志级别:用于分类日志信息的重要性,…

【Spring Boot 入门一】构建你的第一个Spring Boot应用

一、引言 在当今的软件开发领域,Java一直占据着重要的地位。而Spring Boot作为Spring框架的延伸,为Java开发者提供了一种更加便捷、高效的开发方式。它简化了Spring应用的搭建和配置过程,让开发者能够专注于业务逻辑的实现。无论是构建小型的…

齐次坐标的理解

齐次坐标是一种在计算机图形学、计算几何和机器人学中广泛使用的坐标表示方法。它通过引入额外的维度,将传统的欧几里得坐标转换为齐次坐标,从而简化一些数学运算,尤其是在变换(如平移、旋转和缩放)时。 齐次坐标的定…

基于SpringBoot实现QQ邮箱发送短信功能 | 免费短信服务

开发学习过程中有个短信发送功能,阿里云腾讯云等等都要money,听说qq邮箱可以实现免费发送邮箱的功能(短信发送的平替),就用这个来实现!!!【找了好多好多方法才成功的啊啊啊啊&#x…

【MySQL】查询原理 —— B+树查询数据全过程

使用B树作为索引结构的原因: 一种自平衡树: B树在插入和删除的时候节点会进行分裂和合并操作,以保持树的平衡,存在冗余节点,使得删除的时候树结构变化小,更高效。 高度不会增长过快,查询磁盘I…

[大语言模型-论文精读] 悉尼大学-ACL2024-提升大型语言模型的复杂视觉推理能力

[大语言模型-论文精读] 悉尼大学-ACL2024-提升大型语言模型的复杂视觉推理能力 目录 文章目录 [大语言模型-论文精读] 悉尼大学-ACL2024-提升大型语言模型的复杂视觉推理能力目录论文简介0. 摘要2. 相关工作2.1 视觉-语言领域的推理研究2.2 用于视觉-语言分析的大型语言模型 3 …

如何通过SNP Glue简化SAP数据迁移至云数据湖?

有一种更简单的方法可以将关键SAP数据导入云数据湖,而不需要长时间的不可靠数据加载。您还可以仅发送自上次采集后更新的数据,接近于实时地复制数据。我们的专家将向您介绍他们如何使用SNP Glue为我们的客户实现这一点,包括: ■ …

如何提取b站的视频字幕,下载视频

打开视频地址 按F12打开—开发者工具 在开发者工具打开Network 过滤器关键字: 自动生成字幕:ai_subtitle 自制:json 打开/关闭字幕 刷新页面 找到字幕 点选字幕的respond 将方框中的内容复制; 复制到:https://www.drea…