提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言🚀🚀🚀
☀️
要么读书,要么旅游
本文简介:本人是大二软件工程专业,上学期开了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日(晚上十二点再二更的)