【新手入门】JDBC详细介绍丨黑马程序员(学习笔记,适合大一大二)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言🚀🚀🚀

在这里插入图片描述

☀️
要么读书,要么旅游


本文简介:本人是大二软件工程专业,上学期开了Mysql数据库这门课,但是课堂上没有教JDBC的内容(我学jdbc原因:我是java方向的,想做项目,连接数据库要用到这块知识),所以后面是看黑马自学的,通过做笔记分享到博客上的形式,激励自己学习,同时方便复习。
由于水平为入门级别,如有错误,欢迎大佬们评论或私信斧正 Thanks♪(・ω・)ノ


JDBC连接Mysql数据库详解:☀️☀️☀️

1.JDBC简介

1.1 What(JDBC是什么?):

  JDBC(Java DataBase Connectivity),即Java数据库连接JDBC就是用Java语言连接数据库的一套API 。(api:可以理解为Java自己提供的标准类库,开发人员可直接使用其方法)

1.2 JDBC本质:

  官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
各个数据库厂商去实现这套接口,提供数据库驱动jar包,我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。(那么这里其实对JDBC即接口 也好理解了,因为接口就是规定程序要做什么,但不在其中实现。)

1.3 JDBC好处

(1)各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
(2)可随时替换底层数据库,访问数据库的Java代码基本不变


2.JDBC快速入门(步骤:创建空项目+导jar包+代码实现)

  分为如图七个步骤:首先要导入Mysql驱动jar包(驱动jar包:就是Mysql或者Oracle这样的数据库厂商针对于JDBC写的一套实现类,可以去官网下,也可以下下面链接的版本,下完后面才能导入)
也可以看黑马视频一边操作(链接:https://www.bilibili.com/video/BV1Qf4y1T7Hxp=30&vd_source=12384b61e0b367d92ce270fa4eb8fb68)
Mysql驱动jar包下载(这个是黑马视频的版本):链接:https://pan.baidu.com/s/1ZNRUcuTjt6qcS1R7zZXivQ
提取码:5520

来自黑马程序员


接下来为创建工程,导入Mysql驱动jar包过程:

2.1 New Project

先创建一个Empty Project(jdbc01):
在这里插入图片描述

2.2 简单配置工程Project

创建完后,需要对这个工程进行一些简单的配置:(jdk配置这里黑马课程建议是用1.8版本)
在这里插入图片描述
调完配置后apply然后OK即可:
在这里插入图片描述

2.3 配置完后,创建一个模块

(由于我的idea版本是2022版,跟黑马视频里面的不太一样,所以我创建完空项目后会自动生成一个模块,这里不用管它)接着跟黑马视频操作:
在这里插入图片描述
在这里插入图片描述
创建好模块后,就可以在这个模块里面写代码了:下图为项目目录结构
在这里插入图片描述

2.4 导入驱动jar包

创建完模块后第一件要做的事是导入驱动jar包,一般jar包会单独放在一个目录下面,故创建一个lib目录,然后将准备好的jar包复制过来。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复制好了后没完,还需要让当前这个工程来识别这个jar包,我们需要右键jar包,然后Add as library,在level栏中选一下jar作用范围,这里我们选Module Library。如图所示:
在这里插入图片描述
在这里插入图片描述
点击OK,这样我们的驱动jar包和工程都搞好了,下来我们就可以开始写代码了。(到这里其实成功了很大步了,后面就开始真正的学习勒🍓)


2.5 代码实现(知识点非常多!!!)

  下图我已经创建了一个包名为jdbc的包,并创建JDBCDemo类(用来存放代码)。
在这里插入图片描述
笔记:(以下黑体字部分对象与方法后面会详讲,勿慌)
  (1)首先第一步注册驱动,调用Class类中的forName()方法,这个路径也是固定的(故这里其实记着就行了)
  (2)然后获取连接这里用到DriverManager对象中的getConnection()方法,有三个参数url,username,password,分别对应要连接数据库的url(根据端口号以及数据库名来写,是有格式的"jdbc:mysql://+端口号/+数据库名",不用死记硬背,一般默认端口号3306就可以省略,如上图可写为jdbc:mysql:///db1,注意是三条/)账号名及密码。
  (3)最后一步要记得释放资源


代码理解+小结:

  这里的DriverManager对象中的getConnection方法() 调用后会有一个返回值,是Connection对象,故用一个Connection对象接收。
conn对象里面有个createStatement()方法可以获取到Statement对象获取执行sql的对象
在这里插入图片描述
这里创建了stmt执行对象,故可调用execteUpdate()方法执行sql语句,会返回一个受影响的行数结果,意思如上图所示:

但是如果是执行DDL语句(比如drop操作)操作将可能出现特殊情况,如下图:出现了0

  tip: 看到这里小伙伴们可能会吐槽:这么多从未见过的对象和方法,这还记个集贸啊0.0
但是各位不要慌,我个人理解:其实这些方法你看得懂,能理解就行,接下来最常用用的也就这几个对象与方法,你会使用,稍微修改就行,而且熟能生巧,或许敲多了潜移默化中也记住了。

分割线

3.JDBC API详讲

3.1 DriverManager(驱动管理类)

作用:
1.注册驱动
2.获取数据库连接


3.1.1 两个常见的方法:

  我们看一下官方文档,DriverManager类有非常多的静态方法,我们直接调用即可,然后我们只需记住常用的方法(如getConnection)
在这里插入图片描述

  其实也只需要先记两个方法,上面一个,还有一个就是下面这个registerDriver()方法,用于注册给定的驱动程序,那么有趣的是我们前面明明不是用这个方法,我们用的是这个,这又是怎么回事呢?
在这里插入图片描述
在这里插入图片描述
顺着黑马的视频我们点开com.mysql.jdbc.Driver这里的Driver类的源码
在这里插入图片描述
  我们发现原来真正注册驱动是由这个registerDriver()方法注册的,所以上面那个Class类.forName() 方法其实最后底层还是用到这个registerDriver()方法


3.1.2 可以省略注册步骤的原因: 如下图所示(自动读取了类名)

在这里插入图片描述在这里插入图片描述
细节:
在这里插入图片描述
  第一点前面有说明了,第二点什么意思呢?如下图(虽然没有错误,但是还是会报出这么一条红色信息,原因就是Mysql5.7 比较高的版本,这个版本建议我们使用一个更加安全的连接方式SSL,我们不使用,原因是使用这个连接方式需要复杂的配置,而且性能大概会降低百分之20左右)
在这里插入图片描述

我们只需要改在url这里把db1后面加?useSSL=false这条语句,然后就可以了。

在这里插入图片描述
在这里插入图片描述

3.2 Connection(数据库连接对象)

作用:
1.获取执行 SQL 的对象
2.管理事务


3.2.1 官方文档(Connection是一个接口)

看了一下官方文档可以发现其实Connection是一个Interface(接口) :

在这里插入图片描述

Connection对象涉及到三个方法(全都是用来获取执行对象):这里看不懂没关系,后面多看代码就渐渐懂了。

在这里插入图片描述


3.2.2 事务管理:

第一张图先让大家回忆一下Mysql事务管理那一块的知识:

在这里插入图片描述
第二张是JDBC事务管理:

在这里插入图片描述
这里用java代码实现事务回滚的过程,要么同时执行两条sql语句,要么同时不执行(异常处理+回滚)
代码:

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

public class JDBCDemo3_Connection {
    public static void main(String[] args) throws Exception {
        //1. 注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        String url = "jdbc:mysql:///db1?useSSL=false";
        String username = "root";
        String password = "12345678";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3. 定义sql
        String sql1 = "update account set money = 3000 where id = 1";
        String sql2 = "update account set money = 3000 where id = 2";
        //4. 获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        try {
            // 开启事务
            conn.setAutoCommit(false);
            //5. 执行sql
            int count1 = stmt.executeUpdate(sql1);//受影响的行数
            //6. 处理结果
            System.out.println(count1);
            int i = 3/0;
            //5. 执行sql
            int count2 = stmt.executeUpdate(sql2);//受影响的行数
            //6. 处理结果
            System.out.println(count2);

            // 提交事务
            conn.commit();
        } catch (Exception throwables) {
            // 回滚事务
            conn.rollback();
            throwables.printStackTrace();
        }
        //7. 释放资源
        stmt.close();
        conn.close();
    }
}

打开Navicat,db1数据库内表的情况为下图所示,然后我们执行上面代码后(由于 i = 3/0 会报异常,故会执行conn.rollback() 语句回滚事务,我们看到最终数据还是一样没变)

在这里插入图片描述

执行后的结果:

在这里插入图片描述

3.3 Statement
3.3.1 Statement作用:

1.执行 SQL 语句
2.判断SQL是否执行成功(异常处理,加个判断:executeUpdate() 方法返回的结果若大于0说明执行成功,但此方法针对DML语句)


3.3.2 Statement的两种常用方法

我们知道SQL有三种类型:DML、DDL、DQL
Statement就提供了如下两种方法来执行这三种SQL:

在这里插入图片描述
可以看到executeQuery()方法返回的是ResultSet对象,这个到下面再讲,然后executeUpdate是返回一个结果集上面也有例子。这里的细节上面也介绍了:如果是执行DDL语句(比如drop操作)操作将可能出现特殊情况
在这里插入图片描述

3.4 ResultSet(结果集对象)
3.4.1 作用:

1.封装了DQL查询语句的结果


  ResultSet把查询结果封装起来,然后里面会有个游标,游标会默认指向第一行(也就是字段那一行)需要操作游标,故ResultSet有以下两个方法。
在这里插入图片描述

在这里插入图片描述

  上面的Xxx并不是方法名,而是代表了很多数据类型的意思(int / String等等)。
为了提高效率,写了下面这个循环判断来获取数据:
在这里插入图片描述

3.4.2 主要代码:
		//  省略部分代码
        //5. 执行sql
        ResultSet rs = stmt.executeQuery(sql);
		//  省略部分代码
        // 6.1 光标向下移动一行,并且判断当前行是否有数据
        while (rs.next()){
            Account account = new Account();
            //6.2 获取数据  getXxx()
            int id = rs.getInt("id");
            String name = rs.getString("name");
            double money = rs.getDouble("money");
            //赋值
            account.setId(id);
            account.setName(name);
            account.setMoney(money);
            // 存入集合
            list.add(account);
        }
        int id = rs.getInt("id");
        String name = rs.getString("name");
        double money = rs.getDouble("money");

上面三行代码也可改成:

        int id = rs.getInt(1);
        String name = rs.getString(2);
        double money = rs.getDouble(3);

ResultSet对象就会默认1,2,3是列的编号,故运行结果不变。

  


3.5 PreparedStatement(继承Statement)
3.5.1 PreparedStatement作用:

1.预编译SQL语句并执行
2.预防SQL注入问题


3.5.2 什么是SQL注入?

在这里插入图片描述
  简单说就是当你登录账号时,除了用正确的账号密码登录成功外,还可以账号随便写,密码写一代特殊的SQL脚本,然后登录成功(这样的系统及其不安全)。

这里分享一个细节:就是下面这个字符串如何改拼接:
在这里插入图片描述
上面的xx和sss分别写对应的用户名和密码,方法:先写两个双引号再+号,然后把name放中间即可,如下图:
在这里插入图片描述


接下来分析sql注入用奇葩密码能登录成功的原因:
首先将pwd改成下图一个奇葩的密码:
在这里插入图片描述
原因其实跟sql的字符串拼接有关
咱们先打印一下sql结果,然后将输出结果复制到navicat表查询编辑器上面,好好研究一下:
在这里插入图片描述
在这里插入图片描述
分析:
  首先and会比or先执行,故先判断 username = ‘hfkjsfhskj’ and password = ’ ’ 是false,然后后面or ‘1’ = ‘1’ 为true,那么是不是无论username 为何值,这个长式子都会为true,故可以执行。(这个也是bug出现的原因)
  目前很多网站都防止SQL注入,如果你写代码存在SQL注入的话,那大概率是会被炒鱿鱼吧哈哈。

3.5.3 如何解决SQL注入问题?

  因为之前就是因为字符串拼接导致出的问题,现在改用 ? 当占位符:如下图所示,再结合代码更好理解。然后通过setXxx给 ? 赋值。这里还有在执行SQL这个步骤有变化:不需要再传递SQL,因为在通过Connetion对象获取的时候已经传入对应的sql语句了。
在这里插入图片描述
用刚才那个奇葩密码测试一下,如图所示登录失败,说明确实解决了sql注入的问题。
在这里插入图片描述
  那到底是如何解决的呢?其实是因为这个PreparedStatement 在设置 ? 的时候会对参数进行转义
,如下图:
在这里插入图片描述
在这里插入图片描述
  它会判断哪些是关键字,然后帮你转义,也就解决了原先字符串导致的SQL注入的问题。


在这里插入图片描述

总结:🍓🍓🍓

碎碎念:
  感谢小伙伴能看到这里!!!有一说一,今天是从早上十一点到自习室,然后中间吃了晚饭因为早饭十点半吃就没吃午饭(下次再也不敢了,要饿憋了)直接肝到现在是晚上九点三十,终于把上次看完黑马的JDBC那一块知识笔记全部整理完。然后接下来Java的学习规划:ssm,也有打算做学习笔记发到博客上。
学习建议:
  JDBC这一部分建议是要先有数据库的基础才可以学,不过内容也不算多,如果你能从头到尾认真看下来并且思考,你至少是汲取了这篇文章百分之八十以上的知识,对JDBC也肯定是有了一个入门级别的了解,够用了。
End:
  时间真咻一下就来到十二点,认真珍惜享受当下,跟看到这里的人以及未来的我一同共励志、共勉。
                                  一一2024年5月12日(晚上十二点再二更的)

Alt

最近更新

  1. TCP协议是安全的吗?

    2024-05-13 13:28:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-13 13:28:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-13 13:28:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-13 13:28:02       20 阅读

热门阅读

  1. Python如何传送我的世界Spigot服务器中的玩家

    2024-05-13 13:28:02       13 阅读
  2. 前端video标签播放第三方外链地址报错403

    2024-05-13 13:28:02       11 阅读
  3. 02-SpringApplication.run

    2024-05-13 13:28:02       12 阅读
  4. Map、Set和Object的区别

    2024-05-13 13:28:02       10 阅读
  5. Vue3知识总结-3

    2024-05-13 13:28:02       9 阅读
  6. del删除脚本的“无效开关”

    2024-05-13 13:28:02       8 阅读
  7. TypeScript 类型系统深度解析:类型全览

    2024-05-13 13:28:02       13 阅读
  8. vue的生命周期

    2024-05-13 13:28:02       10 阅读
  9. day5.12 leetcode80 删除有序数组重复项

    2024-05-13 13:28:02       14 阅读
  10. Leetcode 3148. Maximum Difference Score in a Grid

    2024-05-13 13:28:02       13 阅读
  11. 即将研究生入学,记录一些遇到的疑问

    2024-05-13 13:28:02       10 阅读
  12. linux的Wget命令下载文件示例

    2024-05-13 13:28:02       13 阅读
  13. 如何在Python中自定义异常?

    2024-05-13 13:28:02       9 阅读
  14. JVM调优:JVM常用调优命令和参数

    2024-05-13 13:28:02       11 阅读