JDBC 技术( mysql 8.0.26 JDK 21 尚硅谷最新版 4h)
基础篇
:以解决现有问题的角度,快速学习 JDBC 的基础应用,让学员以最低的学习成本上手使用 JDBC
一,引言
1.1 数据的存储
我们在开发Java程序时,数据都是存储在内存中,属于临时存储,当程序停止或重启时,内存中的数据就丢失了!我们为了解决数据的长期存储问题,有如下解决方案:
- 数据通过 I/O 流技术,存储在本地文件中,解决了持久化问题,但是没有结构和逻辑,不方便管理和维护。
- 通过关系型数据库,将数据按照特定的格式交由数据库管理系统维护。关系型数据库是通过库和表分隔不用的数据,表中数据存储的方式是行和列,区分相同格式不同值的数据
1.2 数据的操作
数据存储在数据库,仅仅解决了我们数据存储的问题,但当我们程序运行时,需要读取数据,以及对数据做增删改查的操作,那么我们如何通过Java程序对数据库中的数据做增删改查呢?
二,JDBC
2.1概念
- JDBC: Java Database java jdbc基础教学 Connectivity, 意为 Java 数据库连接
- JDBC 是 Java 提供的一组独立于任何数据库管理系统的 API.
- Java 提供接口规范,由各个数据库厂商提供接口的实现,厂商提供的实现类封装成 jar 文件,也就是我们俗称的数据库驱动 jar 包。
- 学习 JDBC, 充分体现了面向接口编程的好处,程序员只关心标准和规范,而无需关注实现过程。
2.2 JDBC的核心组成
- 接口规范:
- 为了项目代码的可移植性,可维护性,SUN 公司从最初就制定了Java程序连接各种数据库的统一接口规范。这样的话,不管是连接哪一种 DBMS 软件,Java 代码可以保持一致性。
- 接口存储在 java.sql 和 javax.sql 包下。
- 实现规范:
- 因为各个数据库厂商的 DBMS 软件各有不同,那么各自的内部如何通过 SQL 实现增、删、改、查等操作管理数据,只有这个数据库厂商自己更清楚,因此把接口规范的实现交给各个数据库厂商自己实现。
- 厂商将实现内容和过程*封装成 jar 文件,我们程序员只需要将 jar 文件引l入到项目中集成即可,就可以开发调 用实现过程操作数据库了。(一般第三方 jar 放在 lib 文件下)
三,JDBC 快速入门
连接数据库, 创建学习项目
四,核心API理解
4.1 注册驱动
- 在Java中,当使用 JDBC(Java Database Connectivity) 连接数据库时,需要加载数据库特定的驱动程序,以便于数据库进行通信。加载驱动程序的目的时为了注册驱动程序,使得 JDBCAPI 能够识别并与特定的数据库进行交互
- 从JDK6 开始,不再需要显式地调用 Class.forName() 来加载 JDBC 驱动程序,只要在类路径中集成了对应地jar文件,会自动在初始化时注册驱动程序
4.2 Connection
- Connection 接口是 JDBCAPI 的重要接口,用于建立与数据库的通信通道。换而言之,Connection 对象不为
则代表一次数据库连接。 - 在建立连接时,需要指定数据库URL、用户名、密码参数。
- URL: jdbc:mysql://localhost:3306/atguigu
- jdbc:mysql://IP地址:端口号/数据库名称?参数键值对1&参数键值对2
- URL: jdbc:mysql://localhost:3306/atguigu
- Connection 接口还负责管理事务,Connection 接口提供了 commit 和 rollback 方法,用于提交和回滚事务。
- 可以 创建 Statement 对象,用于执行 SQL 语句并与数据库进行交互。
- 在使用 JDBC 技术时,必须要先获取 Connection 对象,在使用完毕后,要释放资源,避免资源占用浪费及泄露
4.3 Statement
- Statement接口用于执行SQL 语句并与数据库进行交互。它是 JDBCAPI 中的一个重要接口。通过
Statement 对象,可以向数据库发送 SQL 语句并获取执行结果。 - 结果可以是一个或多个结果。
- 增删改:受影响行数单个结果。
- 查询:单行单列、多行多列、单行多列等结果。
- 但是 Statement 接口在执行 sQL 语句时,会产生 SQL 注入攻击问题:
- 当使用Statement执行动态构建的 SQL 查询时,往往需要将查询条件与 SQL 语句拼接在一起,直接将参数和 SQL 语句一并生成,让 SQL 的查询条件始终为true得到结果。
4.4 PreparedStatement
- PreparedStatement 是 Statement 接口的子接口,用于执行预编译的 SQL 查询,作用如下:
- 预编译SQL语句:在创建PreparedStatement 时,就会预编译 SQL 语句,也就是 SQL 语句已经固定。
- 防止sQL注入:PreparedStatement 支持参数化查询,将数据作为参数传递到 sQL 语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来",无论传递什么都作为值。有效防止传入关键字或值导致SQL 注入问题。
- 性能提升:PreparedStatement 是预编译 sQL 语句,同一 SQL 语句多次执行的情况下,可以复用,不必每次重新编译和解析。
- 后续的学习我们都是基于 PreparedStatement 进行实现,更安全、效率更高
4.5 ResultSet
- ResultSet 是 JDBC API 中的一个接口,用于表示从数据库中执行查询语句所返回的结果集。它提供了一种用于遍历和访问查询结果的方式。
- 遍历结果:ResultSet 可以使用 next() 方法将游标移动到结果集的下一行,逐行遍历数据库查询的结果,返回值为 boolean 类型,true 代表有下一行结果,false 则代表没有。
- 获取单列结果:可以通过 getXxx 的方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取。
五,基于PrepareStatement实现CRUD
5.1 查询单行单列
5.2 查询单行多列
5.3 查询多行多列
5.4 新增
5.5 修改
5.6 删除
六,常见问题
6.1 资源的管理
在使用JDBC的相关资源时,比如Connection, PreparedStatement, ResultSet, 使用完毕后, 要及时关闭这些资源以释放数据库服务器资源和避免内存泄漏是很重要的。
6.2 SQL语句问题
java.sql.SQLSyntaxErrorException: SQL语句错误异常,一般有几种可能:
- SQL语句有错误,检查SQL语句!建议SQL语句在SQL工具中测试后再复制到Java程序中!
- 连接数据库的URL中,数据库名称编写错误,也会报该异常!
java.sql.SQLSyntaxErrorExeption:
6.3 SQL语句未设置参数问题
java.sql.SQLException: No value specified for parameter 1
在使用预编译SQL语句时,如果有?占位符,要为每一个占位符赋值,否则报该错误
java.sql.SQLSyntaxErrorException:
6.4 用户名或密码错误问题
连接数据库时,如果用户名或密码输入错误,也会报SQLException, 容易混淆,所以一定要看清楚异常后面的原因描述
java.sql.SQLException: Access denied for user ‘root’@‘localhost’ (using password: YES)
6.5 通信异常
在连接数据库的URL中,如果IP或端口写错了,会报如下异常。
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
com.mysql.cj.jdbc.exceptions.CommunicatonsException: Communication link failure
进阶篇
:理解ORM思想,在基础篇内容上做进一步的空间,掌握多种连接池优化程序的能力,以优化程序的能力,以优化角度学习。
七,JDBC扩展
7.1 实体类和ROM
- 在使用JDBC 操作数据库时,我们会发现数据都是零散的,明明在数据库中是一行完整的数据,到了Java 中变成了一个一个的变量,不利于维护和管理。而我们Java是面向对象的,一个表对应的是一个类,一行数据就对应的是Java中的一个对象,一个列对应的是对象的属性,所以我们要把数据存储在一个载体里,
这个载体就是实体类!- ORM(ObjectRelationalMapping)思想,对象到关系数据库的映射,作用是在编程中,把面向对象的概
念跟数据库中表的概念对应起来,以面向对象的角度操作数据库中的数据,即一张表对应一个类,一行数 据对应一个对象,一个列对应一个属性!- 当下JDBC中这种过程我们称其为手动ORM。后续我们也会学习ORM框架,比如MyBatis、JPA等。
方式一
方式二
7.2 主键回显
- 在数据中,执行新增操作时,主键列为自动增长,可以在表中直观的看到,但是在Java程序中,我们执行完新增后,只能得到受影响行数,无法得知当前新增数据的主键值。在Java程序中获取数据库中插入新数据后的主
键值,并赋值给Java对象,此操作为主键回显。- eg:
- eg:
- 代码实现:
小小语法优化
7.3 批量操作
- 插入多条语句,一条一条发送给数据库执行,效率低下!
- 通过批量操作,可以提升多次操作效率
八,连接池
8.1 现有问题
- 每次操作数据库都要获取新连接,使用完毕后就close释放,频繁的创建和销毁造成资源浪费
- 连接的数量无法把控,对服务器来说压力巨大
8.2 连接池
连接池就是数据库连接对象的缓冲区,通过配置,由连接池负责创建连接、管理连接、释放连接等操作。
预先创建数据库连接放入连接池,用户在请求时,通过池直接获取连接,使用完毕后,将连接放回池中,避免了频繁的创建和销毁,同时解决了创建的效率。
当池中无连接可用,且未达到上限时,连接池会新建连接。
池中连接达到上限,用户请求会等待,可以设置超时时间。
8.3 常见连接池
JDBC的数据库连接池使用javax.sql.DataSource接口进行规范,所有的第三方连接池都实现此接口,自行添加具体实现!也就是说,所有连接池获取连接的和回收连接方法都一样,不同的只有性能和扩展功能!
- DBCP是Apache提供的数据库连接池,速度相对C3Po较快,但自身存在一些BUG。
- C3P0是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以。
- Proxool是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3po差一
- Druid是阿里提供的数据库连接池,是集DBCP、C3PO、Proxool优点于一身的数据库连接池,性能、扩展
性、易用性都更好,功能丰富。 - Hikari(U办[shigalij)取自日语,是光的意思,是SpringBoot2.x之后内置的一款连接池,基于BoneCP(已经放弃维护,推荐该连接池)做了不少的改进和优化,口号是快速、简单、可靠。
Druid与Hikari对比
8.4 Druid连接池使用
- 使用步骤
- 引入jar包
- 编码
- 代码实现
- 硬编码方式(了解)
软编码方式(推荐):
- 在项目目录下创建resources文件夹, 标识该文件夹为资源目录, 创建db.properties配置文件,将连接信息定义在该文件中.
-
- Java代码
- 在项目目录下创建resources文件夹, 标识该文件夹为资源目录, 创建db.properties配置文件,将连接信息定义在该文件中.
8.5 Druid其它配置[了解]
视频未提及!!!。
8.6 HikariCP连接池使用
- 使用步骤
- 引入jar包
- 硬编码方式:
- 软编码方式
8.7 HikariCP其他配置[了解]
视频尚未提及!!!。
高级篇
:在掌握进阶篇内容后,融入实战经验的封装,优化,功能流程的把控,强化开发项目思想,优化代码逻辑。
九,JDBC优化及工具类封装
9.1 现有问题
我们在使用JDBC的过程中,发现部分代码存在冗余的问题
- 创建连接池。
- 获取连接。
- 连接的回收。
9.2 JDBC工具类封装V1.0
- resources / db.properties 配置文件
- 工具类代码:
9.3 ThreadLocal
JDK1.2的版本中就提供java.lang.ThreadLocal,为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。通常用来在在多线程中管理共享数据库连接、Session等。
ThreadLocal用于保存某个线程共享变量,原因是在Java中,每一个线程对象中都有一个ThreadLocalMap<ThreadLocal,Object>,其key就是一个ThreadLocal,而object即为该线程的共享变量。
而这个map是通过ThreadLocal的set和get方法操作的。对于同一个staticThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。
- 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
- 线程间数据隔离。
- 进行事务操作,用于存储线程事务信息。
- 数据库连接,Session会话管理。
- 1、ThreadLocal对象.get: 获取ThreadLocal中当前线程共享变量的值。
- 2、ThreadLocal对象.set: 设置ThreadLocal中当前线程共享变量的值。
- 3、ThreadLocal对象.remove:移除ThreadLocal中当前线程共享变量的值。
9.4 JDBC工具类封装V2.0
十,DAO封装及BaseDAO工具类
10.1 DAO概念
DAO: DataAccessObject,数据访问对象。
Java是面向对象语言,数据在Java中通常以对象的形式存在。一张表对应一个实体类,一张表的操作对应一个DAO对象!
在Java操作数据库时,我们会将对同一张表的增删改查操作统一维护起来,维护的这个类就是DAO层。
DAO层只关注对数据库的操作,供业务层Service调用,将职责划分清楚!
10.1 BaseDAO概念
基本上每一个数据表都应该有一个对应的DAO接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以可以抽取公共代码,给这些DAO的实现类可以抽取一个公共的父类,复用增删改查的基本操作,我们称为BaseDAO。
10.2 BaseDAO搭建
搭建增删改查(注意目录结构也值得学习)
搭建通用查询
搭建查询单个结果
10.3 BaseDAO的应用
十一,事务
11.1 事务回顾
- 数据库事务就是一种SQL语句执行的缓存机制,不会单条执行完毕就更新数据库数据,最终根据缓存内的多条语句执行结果统一判定!一个事务内所有语句都成功及事务成功,我们可以触发commit提交事务来结束事务,更新数据!一个事务内任意一条语句失败,即为事务失败,我们可以触发rollback回滚结束事务,数据回
到事务之前状态! - 一个业务涉及多条修改数据库语句!例如:
- 经典的转账案例,转账业务(A账户减钱和B账户加钱,要一起成功)
- 批量删除(涉及多个删除)
- 批量添加(涉及多个插入)
- 事务的特性:
- 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不
发生。 - 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
- 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
- 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不
- 事务的提交方式:
- 自动提交:每条语句自动存储一个事务中,执行成功自动提交,执行失败自动回滚!
- 手动提交:手动开启事务,添加语句,手动提交或者手动回滚即可
11.2 JDBC中事务实现
- 关键代码
11.3 JDBC事务代码实现
-
准备数据库表
-
DAO接口代码
-
DAO实现类代码
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/h6javajc/1871.html