
🔥个人主页: 寻星探路
🎬作者简介:Java研发方向学习者
📖个人专栏:、《
⭐️人生格言:没有人生来就会编程,但我生来倔强!!!
目录
[1、DriverManager 和DataSource](#1、DriverManager 和DataSource)
[2、DriverManager 与DataSource的区别](#2、DriverManager 与DataSource的区别)
[3、Connection 数据库连接](#3、Connection 数据库连接)
一、什么是JABC
JDBC(Java Data Base Connectivity,Java数据库连接)是Java程序和数据库之间的桥梁,包含了⼀套Java定义的用于执行SQL语句的接口,使开发者能够编写数据库的程序。JDBC的主要作用是: 与数据库建立连接、发送SQL语句和处理数据库执行结果。


1、JDBC的应用场景
如果JAVA要访问不同的数据库,那么就需要根据数据库的协议进行代码的开发
为了解决不同数据的使用场景,JAVA中只定义了用于连接和操作数据的接口--JDBC
具体的实现由数据库厂商来完成
2、JDBC工作原理
JDBC工作原理简洁地概括为:加载驱动、建立连接、创建Statement、执行SQL、处理结果和关闭资源。
二、为什么要使用JDBC
• 首先回顾⼀下使用客户端操作数据库的过程,主要分为以下几步:
a. 连接到数据库服务
b. 发送SQL语句
c. 得到返回结果并显示
d. 关闭连接
对于JAVA程序员来说,只需要调用JDBC定义的方法就可完成数据库的具体操作
• 同样如果使用程序操作数据库也会经历以上几步,⼤家应该可以想到,为实现上述步骤,可以编写相应的代码实现数据库连接,发送SQL语句,处理结果并显示,最后关闭连接。
• 但是不同的数据库对于同⼀个操作不论是协议还是参数都各有不同,如果让程序员自己去实现,那就必须针对不同的数据库进行编码实现,这个工作量和维护成本显然太大。
• Java采取的做法是把以上操作步骤定义了相应的接口,具体的实现交给数据库厂商去做,Java程序员只需要按照需要调用接口中定义的方法即可,这样不论使用什么数据库,都对于Java程序没有任何影响,即便是换⼀个数据库,也只需要换⼀下相应厂商的实现依赖。
• JDBC使用过程可以概括为:加载数据库厂商的驱动包、建立连接、创建Statement、执行SQL、 处理结果释放资源和关闭连接。
三、使用JDBC
1、创建Maven工程并配置国内镜像
1.1创建Maven工程

1.2配置国内镜像(阿里的)

拖动到idea里面,把<mirrors></mirrors>中的内容换成下面的内容,再CTRL+s(保存)
(默认的仓库在国外,我们下载会很慢,所以要换成国内的镜像)
html
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿⾥云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
<mirror>
<id>central</id>
<mirrorOf>*</mirrorOf>
<name>aliyun central</name>
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
<mirror>
<id>spring</id>
<mirrorOf>*</mirrorOf>
<name>aliyun spring</name>
<url>https://maven.aliyun.com/repository/spring</url>
</mirror>
2、获取MySQL驱动包
在Maven仓库(mvnrepository.com)搜索MySQL,找到最新版的驱动包

一般8.0.33就可以
3、修改pom.xml⽂件
在⼯程中的pom.xml中的新建<dependencies></dependencies>标签中添加MySQL依赖(把上图最下面的代码复制粘贴到<dependencies></dependencies>中间)
加载成功后可以通过以下方式查看

4、建立数据库连接
使用驱动管理类 DriverManager 的静态方法获取数据库连接
java
// 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取数据库连接
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jobs_info_db?characterEncoding" +
"=utf8&allowPublicKeyRetrieval=true&useSSL=false",
"root",
"123456");
通过数据源 DataSource 对象获取,推荐在实际开发中应用这种方式
java
// 设置数据源的连接串、⽤⼾名和密码
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/jobs_info_db?characterEncoding" +
"=utf8&allowPublicKeyRetrieval=true&useSSL=false");
mysqlDataSource.setUser("root");
mysqlDataSource.setPassword("123456");
// 把mysqlDataSource 转换为JDBC的dataSource
DataSource dataSource = mysqlDataSource;
MySQL数据库连接URL格式: jdbc:mysql:// 服务器地址 : 端⼝ / 数据库 ? 参数名 = 值 [& 参数名 = 值 ]...
5、创建Statement
Statement是用于执行静态SQL语句并返回执行结果的对象
java
// 通过connection获取statement对象
Statement statement = connection.createStatement();
6、执行SQL语句
执行select查询时返回的是⼀个结果集,用ResultSet接收
执行nsert,update,delete操作时,返回的是受影响的行数,用int类型接收
java
// 执⾏select语句, 并接收结果集
ResultSet resultSet = statement.executeQuery("select id, name, sno, age, gender, enroll_date, class_id from student");
// 执⾏insert, update, delete语句,并接收受影响的⾏数
int row = statement.executeUpdate("update student set age = 20 where id = 2");
7、处理结果集
如果返回的是⼀个结果集,则需要遍历这个集合获取对应列的值,具体代码如下:
java
// 遍历结果集获取数据
while (resultSet.next()) {
// 编号
long id = resultSet.getLong("id");
// 姓名
String name = resultSet.getString("name");
// 学号
String sno = resultSet.getString("sno");
// 年龄
int age = resultSet.getInt("age");
// 性别
byte gender = resultSet.getByte("gender");
// ⼊学时间
Date enrollDate = resultSet.getDate("enroll_date");
// 班级编号
long classId = resultSet.getLong("class_id");
// TODO: 使⽤获取到的值...
}

8、释放资源
在整个数据库访问过程中创建的对象都需要释放,包括:ResultSet,Statement和Connection, 后创建的先释放
java
// 释放结果集
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 释放statement
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 关闭连接
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
四、JDBC常用接口和类
1、DriverManager 和DataSource
DataSource驱动管理类,用于管理JDBC驱动程序,可以从驱动程序中获取数据库连接,始于 JDK1.1。
DataSource数据源是DriverManager的替代方案,始于JDK1.4,是获取数据库连接的首选方法, 推荐使用。
2、DriverManager 与DataSource的区别
DriverManager和DataSource都可以获取到数据库连接,但它们之间存着着⼀些区别,主要在于连接的管理方式和资源利用效率
连接管理方式不同:
DriverManager每次调用getConnection方法都会初始化⼀个新的连接,使用完成后会关闭真实连接,导致资源浪费
DataSource使用了连接池的技术,会在初始化时创建⼀定数量的数据库连接,这些连接可以重复使用,关闭时并不是真正关闭连接,而是将连接归还给连接池,以供后续使用,有效地提高资源利用率和和性能
3、Connection 数据库连接
数据库连接(会话)对象,在连接的上下文中执行SQL语句并返回结果
4、Statement对象
4.1Statement
用于执行静态SQL语句并返回执行结果,由于只能执行静态语句,所以这⾥会有⼀个问题,假设⼀个语句中需要动态的参数,如where子句中的条件,那么只能通过字符串拼接的方式组装完成的SQL语句,如:
java
String sql = "select * from student where name = '" + name + "' and class_id = " + classId;
字符串拼接形式构造SQL语句时,如果不处理参数中的特殊字符就会造成SQL注入,这是⼀个非常严重的安全性问题。
4.2SQL注入
SQL注入即是指web应用程序对用户输⼊数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进⼀步得到相应的数据信息。
大家一定不要去做没有授权的安全测试
4.3PreparedStatement
预编译SQL语句对象,SQL语句被预编译并存储在PreparedStatement对象中,可以使用该对象多次执行SQL语句,同时可以解决SQL注入问题。
例:通过Connection对象获取到PreparedStatement对象,需要传入SQL模板,动态参数用占位符?表示
java
// 获取了个处理SQL的PrepareStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("select id, name, sno, age, gender, enroll_date, class_id from student where name = ? and class_id = ?");
为动态参数设置真实值,下标从1开始
java
// ⽤真实值去替换占位符
preparedStatement.setString(1, "宋江");
preparedStatement.setLong(2, 2);
执行SQL语句
java
// select 操作
ResultSet resultSet = statement.executeQuery();
// insert, update, delete操作
int result = statement.executeUpdate();
4.4CallableStatement
用于执行SQL存储过程的接口。这里不做讨论
4.5executeQuery()
执行结果返回的是⼀个结果集,通常用于select操作
4.6executeUpdate()
执行结果返回的是⼀个整形,通常用于insert,update,delete操作
5、ResultSet结果集
是⼀个查询结果集的数据表,通常由执行查询操作的语句生成。
ResultSet对象维护了⼀个指向当前数据行的游标,最初游标位于第一行之前,调用next方法将游标移动到下⼀行,当ResultSet中没有更多的数据行时返回false,所以可以在while循环中使用它来遍历结果集。
ResultSet接口提供了getter⽅法(getBoolean、getLong等),用于从当前行检索列值,可以使用列的索引号或列的名称来检索值。⼀般来说,使用列索引会更有效率,索引编号从1开始,按照从左到右的顺序读取。
六、示例
查询学生编号为1的学生基本信息
java
package org.bitejiuyeke;
import com.mysql.cj.jdbc.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.*;
import java.text.MessageFormat;
public class Demo_DataSource {
public static void main(String[] args) {
// 定义数据源
DataSource dataSource = null;
// 定义连接对象
Connection connection = null;
// 定义预编译对象
PreparedStatement statement = null;
// 定义结果集对象
ResultSet resultSet = null;
// 设置数据源参数
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java01?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
mysqlDataSource.setUser("root");
mysqlDataSource.setPassword("123456");
// 转为JDBC数据源
dataSource = mysqlDataSource;
// 获取连接
try {
connection = dataSource.getConnection();
// 获取了个处理SQL的PrepareStatement对象
statement = connection.prepareStatement("select id, name, sno, age, gender, " +"enroll_date, class_id from student where id = ?");
// ⽤真实值去替换占位符
statement.setLong(1, 1);
resultSet = statement.executeQuery();
// 处理结果集,由于查询的是⼀条记录,这⾥⽤if即可
if (resultSet.next()) {
long id = resultSet.getLong("id");
String name = resultSet.getString("name");
String sno = resultSet.getString("sno");
int age = resultSet.getInt("age");
byte gender = resultSet.getByte("gender");
Date enrollDate = resultSet.getDate("enroll_date");
long classId = resultSet.getLong("class_id");
// 打印结果
System.out.println(MessageFormat.format("{0}, {1}, {2}, {3}, {4}, {5}, {6}", id, name, sno, age, gender,enrollDate, classId));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 在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();
}
}
}
}
}