# JDBCStudy **Repository Path**: aluvfy/JDBCStudy ## Basic Information - **Project Name**: JDBCStudy - **Description**: 本仓库系统性地整理了我学习 JDBC 过程中的核心知识、最佳实践与深度思考。JDBC 不仅是 Java 操作数据库的 API,更是理解后续所有持久层框架(如 MyBatis, Hibernate)的基础。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-15 - **Last Updated**: 2025-09-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: JDBC, Java, MySQL ## README # JDBCStudy https://www.bilibili.com/video/BV19T421174Q/?spm_id_from=333.976.0.0&vd_source=b15db8d2869cc93b5ddd3a0fad088de4 ### 1 JDBC概述 #### 1.1 什么是JDBC? - JDBC(Java DataBase Connectivity),是Java数据库连接,就是Java语言操作数据库 - JDBC是Java语言连接数据库的一套API(Java Application Programming Interface(Java应用程序编程接口(一套类库)) + API三项通常包括API字节码、APi源码、API帮助文档 - 原来操作数据库是在控制台使用SQL语句来操作数据库,JDBC是使用Java语言向数据库发送SQL语句 - 说白了 JDBC就是一套类库 #### 1. 2 JDBC的本质理解 - SUN公司为什么将JDBC定义成接口? 1. 让各大数据库厂家和程序员之间解耦合了。 2. 因为数据库类型太多了,不同数据库的底层原理不一样,为了适应不同的数据库操作,JDBC定义成一套接口。 3. 各大数据库厂家写接口的实现,程序员可以直接调用不同的数据库实现类来操作不同的数据库。 - 数据库驱动 大量的不同数据库实现类会打包成不同数据库的jar包,我们管这个jar包叫**数据库驱动,比如:MySql驱动、Oracle驱动、MS SQL Server驱动**。 驱动的本质是什么? 一套.class字节码文件,这些.class字节码文件是JDBC接口的实现类,这些实现类会被统一放到一个jar文件中管理,我们把XXX.jar文件称为驱动。 - 调用不同的数据库驱动来操作数据库时,配置.properties的driver,通过反射机制创建对象,多态转换后面向jdbc编程,完全实现解耦合,不用更改Java代码,通过更改.properties的配置驱动就可以切换不同的数据库驱动,来操作不同的数据库。 #### 1.3 JDBC驱动的下载配置 - 源码(程序员编写) - 接口(JDK中有包) - 驱动(下载不同的数据库去不同的官网下载) - 在此,MySQL驱动下载:https://dev.mysql.com/downloads/ - 如果要用文本编译器写代码,需要把驱动jar包的路径添加到系统环境变量里,新建CLASSPATH 路径:.;D:\Java\Toolsb\mysql-connector-j-9.0.0\mysql-connector-j-9.0.0.jar (注意前面要加一个.;保证分隔) - 用IDEA不用配环境变量,需要再IDEA里面配置 ### 2 JDBC的增删改dml操作 #### 2.1 JDBC编程六步 1. 注册驱动:告诉Java程序连接得是哪个品牌的数据库(实现类Jar包) 2. 获取数据库连接:mysql和JVM之间的通道打开了 3. 获取数据库操作对象:获取数据库操作对象,发送SQL语句给数据库,一个连接可以有多个操作对象 4. 执行SQL语句:执行SQL语句 5. 处理查询结果集:如果之前的操作是DQL查询语句,才会有有处理查询结果这一步 6. 释放资源:使用完Connection、Statement等,需要用从后依次close显示的关掉 #### 2.2 数据的准备 - PowerDesigner:数据库设计工具 下载:https://link.csdn.net/?from_id=105377215&target=https%3A%2F%2Fonlinedown.rbread04.cn%2Fhuajunsafe%2Fpowerdesigner1029.zip 操作步骤: 1. 创建PDM(Physical Data Model物理数据模型),数据结构存储设计最终转换为数据库逻辑设计的过程,MySQL 2. 建设计表,设置相关参数 3. 保存.sql文件 - Navicat for MySQL:数据库管理工具 添加数据 { 如果使用Mysql数据库开发, Navicat和PowerDesigner相结合可以提高开发效率和数据库质量 } #### 2.3 新增操作 ```java title:inset-step import java.sql.Driver; import java.sql.DriverManager; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; public class JDBCTest01{ public static void main(String[] args){ Connection conn = null; Statement stm = null; //面向接口编程 try{ //1.注册驱动 //com.mysql.cj.jdbc.Driver 是mysql最核心的驱动类 //java.sql.Driver 是接口 Driver driver = new com.mysql.cj.jdbc.Driver();//创建最核心的驱动类 DriverMagager.registerDriver(driver);//注册驱动 //2.获取连接 String url = "jdbc:mysql://localhost:3306/jdbc"; String user = "root"; String passworld = "root"; //调用getcon方法后返回的是实现类对象,多态给conn接口 //conn = com.mysql.cj.jdbc.ConnectionImpl@489115ef //com.mysql.cj.jdbc.ConnectionImpl是mysql厂家对Connnection接口的实现类 ///java.sql.Connection是SUN公司制定的接口 conn = DriverManager.getConnection(url, user, passworld); //3.获取数据库操作对象 stm = conn.createStatement(); System.out.println(stm); //4.执行SQL语句 //这个sql语句最后的分号可以省略 String sql = "insert into t_user(name,password,realname,gender,tel) values('wangwu','12345','王五','男','12345678909')"; //返回值得含义,当sql语句为DQL语句并有查询结果时,返回true //dml语句或者没有结果都返回false //这个语句功能强大(不专业),适合所有SQL语句,很少用。 boolean isSuccess = stm.execute(sql); System.out.println(isSuccess ? "插入失败" : "插入成功"); //凡是执行dml语句(insert,delete,update),建议直接使用executeUpdate方法 int count = stm.executeUpdate(sql); }catch(SQLException e){ e.printStackTrace(); }finally{ //6.释放资源 //原则:从小到大关闭资源 //关闭前最好判断一下是否为空 //分别对其进行try catch (不可以同时try 后面得代码不执行) if(stm != null) { try{ stm.close(); }catch(SQLException e){ e.printStackTrace(); } } if(conn != null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } } } ``` #### 2.4 修改删除操作 ```java title:delete/update-step import java.sql.*; public class JDBCTest02{ public static void main(String[] args){ Connection conn = null; Statement stm = null; try{ //1. 注册驱动 Driver dirver = new com.mysql.cj.jdbc.Driver(); DriverManger.registerDriver(driver); //2. 获取连接 conn = DriverManger.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "root"); //3. 获取数据库对象 stm = conn.createStatement(); //4. 执行SQL语句 String sql = "update t_user set name = 'wuwang', pasword = '112234', realname = '王武', gender = '男', tel = '88888999901', where name = 'wangwu'"; //删除更改sql语句就可以 //String sql = "delete from t_user where name = 'wuwang'"; int count = stm.executeUpdate(sql); System.out.println(count); }catch(SQLException){ }finally{ //6. 释放资源 if (stm != null){ try(){ stm.close(); }catch(SQLException e){ e.printStackTrace(); } } if (stm != null){ try(){ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } } } ``` ### 3 JDBC相关 #### 3.1 URL URL(统一资源定位符),通常由协议、服务器-ip、服务器端口、路径、查询字符串组成。 例如,连接MySQL数据库JDBC URL的格式一般如下: ```c title:mysql-jdbc-url jdbc:mysql://:/? //为连接的额外参数,包括连接超时时间、字符编码格式、连接池等相关配置,其格式为name=value&name=vlaue&.... ``` MySQL URL其他常用的配置: - serverTimezone: MySQL服务器时区默认UTC(全球标准时区),一般不用设置很少,有跨国系统 - useSSL:默认为true,SSL安全传输协议,启用的话加密传输防窃听,但会慢对系统压力会大,所以需要根据不同情况设置 - useUnicode:数据传输过程是否使用Unicode进行编码,默认为True,(为了跨平台正确传输),不管源数据为哪种编码方式 - characterEncoding:设置数据传输到服务器,服务器使用哪种编码方式,默认UTF-8 #### 3.2 注册驱动的方式 ```java title:driver-register-way //way 1 自己new 驱动对象 java.sql.Driver driver = new com.mysql.cj.jdbc.Driver(); java.sql.DriverManger.registerDriver(driver); //way 2 Class.forName("com.mysql.cj.jdbc.Driver"); Class.forName会让传入的字符串路径的类加载,在类加载时里面的静态代码块会执行 ``` JDBC4.(java6)以后,驱动注册不需要手动完成,由系统自动完成。但有少数数据库不支持自动发现功能,仍然需要手动注册,所以建议不省略。 #### 3.3 IDEA开发步骤 1. 创建一个空项目 2. 设置一下JDK、Language Level 3. 创建模块 、 Intellig 4. 创建一个lib文件夹,将mysql-connector.jar复制过来 5. 右键add as library,这套类库就加进去了 6. 进行测试 #### 3.4 数据库连接的多种方式 1. 数据库连接信息可配置 - 配置连接数据库信息文件 - ResourceBundle加载访问资源 2. getConnection(String url, String user, String password) 3. getConnection(url) 4. getConnection(url, info) info(map集合) ### 4 JDBC的查询 1. 通过列索引获取数据 见JDBCTest03.java 2. 通过列名获取数据 见JDBCTest03.java 3. 以指定的数据类型获取数据 见JDBCTest04.java 4. 获取结果集元数据信息 见JDBCTest05.java 5. 获取新增行的主键值 见JDBCTest06.java 6. Dbutils的封装 见JDBCTest07.java 7. 实现用户登录系统 见JDBCTest08.java ### 5 SQL注入 #### 5.1 解决SQL注入问题 - 安全问题:用户提供的信息含有SQL关键字,和sql语句进行字符串拼接后,可能会导致sql语句的含义发生改变(发生扭曲) - 导致SQL注入现象最根本的原因是:先进行了sql语句的字符串拼接,后进行sql语句的编译, - SQL注入是一种安全隐患:攻击者通过向数据库发送恶意的sql语句,从而获取到数据库中的敏感信息 - 怎么避免SQL注入现象呢? java.sql.Statement存在SQL注入现象,因为它的原理是,先进行SQL语句的拼接,然后再进行编译 为了避免SQL注入现象,JDBC API为Statement提供了一个子接口java.sql.PreparedStatement,被称为预编译的数据库操作对象 java.sql.PreparedStatement可以解决SQL注入问题: - 具体怎么解决呢? PreparedStatement可以对SQL语句先进行预编译,再给编译好的SQL语句占位符传值,通过这种方式解决SQL注入问题。 解决示例见JDBCTest09.java - 使用PreparedStatement解决SQL注入问题: PreparedStatement原理: 先对sql语句进行预编译 再将参数值赋值给占位符 重点注意事项: 在使用预编译的数据库操作对象PreparedStatement时,要先获取sql语句,再获取PreparedStatement对象 这里编写的sql语句的 值 的位置采用占位符来代替,占位符为 ? 问好两边不可以使用单引号或者双引号括起来 预处理sql语句(带有?的sql语句) 区别: preparedStatement和Statement都是执行sql语句的接口,他们之间有父子关系;preparedStatement先预编译sql语句然后传值,Statement先拼接字符串后编译;preparedStatement执行速度更快(编译一次,执行n次),可以避免sql注入攻击,并且会做类型检查,是类型安全的; #### 5.2 PreparedStatement的使用 - 新增操作 JDBCTest10.java - 修改操作 JDBCTest11.java - 删除操作 JDBCTest12.java - 模糊查询 JDBCTest13.java - 分页查询 JDBCTest14.java - blob数据的插入和读取 JDBCTest15 / 16.java #### 5.3 JDBC批处理操作 - 不使用批处理 JDBCTest17.java - 使用批处理 JDBCTest18.java ### 6 JDBC事务 1. 什么是事务? 事务是一个完整的业务,在这个业务中需要多条DML语句共可联合才能完成,而事务可以保证多条DML语句同时成功或者同时失败,从而保证数据的安全。例如A账户向B账户转账一万,A账户减去一万(update和B账户加上一万(update),必同时成功或者同时失败,才能保证数据是正确的. 2. 使用转账案例演示事务 - 表和数据的准备 运行t_act.sql - 不考虑事务下实现转账功能 JDBCTest19.java - JDBC事务默认是自动提交的(只要执行一条DML语句,则立即提交一次),如果中间有异常发生,那么不会回滚,导致系统漏洞 JDBCTest19.java - 添加事务控制 第一步:将JDBC事务的自动提交机制修改为手动提交(开启事务) 第二步:当整个业务完成结束后,手动提交业务(即提交事务,事务结束) 第三步:在处理业务中,如果发生异常,则进入catch语句块,手动回滚事务 代码见JDBCTest19.java 3. 设置JDBC事务隔离级别 - 事务有四大特性:原子性、一致性、隔离性、持久性 - 隔离性有四个隔离级别: 代码见 JDBCTest20.java ### 7 JDBC调用存储过程 - 在MySQL中创建存储过程:在MySQL中创建存储过程 ```sql fold title:sql-func //求偶数和的存储过程 CREATE DEFINER=`root`@`localhost` PROCEDURE `mypro`(in n int, out sum int) begin set sum := 0; repeat if n % 2 = 0 then set sum := sum + n; end if; set n := n - 1; until n <= 0 end repeat; end ``` - 使用JDBC代码调用存储过程 JDBCTest21.java ### 8 JDBC实现员工管理 - 数据库表准备 - 实现效果 1. 查看员工列表 2. 查看员工详情 3. 新增员工 4. 修改员工 5. 删除员工 6. 退出系统 - 代码见JDBCTest22.java ### 9 DAO #### 9.1 什么是DAO? - DAO是:Data Access Object,翻译为:数据访问对象 - 一种JavaEE的设计模式,专门用来做数据增删改查的类。 - 在实际的开发中,通常我们会将数据车的操作封装为一个单独的DAO去完成,这样做的目的是:提高代码的复用性,另外也可以降低程序的耦合度,提高扩展力 - 例如:操作用户数据的叫做UserDao,操作员工数据的叫做EmployeeDao,操作产品数据的叫做Product Dao,操作订单数据的做OrderDao等。 #### 9.2 使用DAO改装员工信息管理 1. 定义Employee封装数据 benas.Employee 2. 定义EmployeeDao,并实现CRUD dao.EmployeeDao 3. 员工信息管理DAO改造 JDBCTest23.java #### 9.3 BaseDao的封装 - BaseDao通用更新方法 - BaseDao通用查询方法 - 测试BaseDao ### 10 连接池 #### 10.1 连接池的理解 1. 不使用连接池有啥问题? - Connection.对象是重量级对象,创建Connection对象就是建立两个进程之间的通信,非常耗费资源。一次完整的数据库操作,大部分时间都耗费在连接对象的创建。 - 第一个问题:每一次请求都创建一个Connection连接对象,效率较低。 - 第二个问题:连接对象的数量无法限制。如果连接对象的数量过高,会导致ysq数据库服务器崩溃。 2. 使用连接池来解决什么问题 - 提前创建好N个连接对象,将其存放到一个集合中(这个集合就是一个缓存)。 - 用户请求时,需要连接对象直接从连接池中获取,不需要创建连接对象,因此效率较高。 - 另外,连接对象只能从连接池中获取,如果没有空闲的连接对象,只能等待,这样连接对象创建的数量就得到了控制。 3. javax.sql.DataSource - 连接池有很多,不过所有的连接池都实现了 javax.sql.DataSource 接口。也就是说我们程序员在使用连接池的时候,不管使用哪家的连接池产品,只要面向javax.sql.DataSource接口调用方法即可。 - 另外,实际上我们也可以自定义属于我们自己的连接池。只要实现DataSource接口即可。 4. 连接池的属性 对于一个基本的连接池来说,一般都包含以下几个常见的属性: - 初始化连接数(initialSize):连接池初始化时创建的连接数。 - 最大连接数(maxActive):连接池中最大的连接数,也就是连接池所能容纳的最大连接数量,当连接池中的连接数量达到此值时,后续请求会被阻塞并等待连接池中有连接被释放后再处理。 - 最小空闲连接数量(minIdle): 指连接池中最小的空闲连接数,也就是即使当前没有请求,连接池中至少也要保持一定数量的空闲连接,以便应对高并发请求或突发连接请求的情况。 - 最大空闲连接数量(maxIdle): 指连接池中最大的空闲连接数,也就是连接池中最多允许保持的空闲连接数量。当连接池中的空闲连接数量达到了maxIdle设定的值后,多余的空闲连接将会被连接池释放掉。 - 最大等待时间(maxWait):当连接池中的连接数量达到最大值时,后续请求需要等待的最大时间,如果超过这个时间,则会抛出异常。 - 连接有效性检查(testOnBorrow、testOnReturn):为了确保连接池中只有可用的连接,一些连接池会定期对连接进行有效性检查,这里的属性就是配置这些检查的选项。 - 连接的driver、url、user、password等。 以上这些属性是连接池中较为常见的一些属性,不同的连接池在实现时可能还会有其他的一些属性,不过大多数连接池都包含了以上几个属性,对于使用者来说需要根据自己的需要进行灵活配置。 #### 10.2 常见的连接池 市面上常用的数据库连接池有许多,以下是其中几种: - DBCP : 2001 - c3p0 :2004 - Druid : a. 2012年诞生 b. Druid是一个具有高性能、高可靠性、丰富功能的数据库连接池,不仅可以做连接池,还能做监控、分析和管理数据库,支持SQL防火墙、统计分析、缓存和访问控制等功能 - HikariCP a. 2012年诞生 b. 它被认为是Java语言下最快的连接池之一,具有快速启动、低延迟、低资源消耗等优点。HikariCP连接池适用于高并发场景和云端应用 c. 很单纯的一个连接池,这个产品只做连接池应该做的,其他的不做。所以性能是极致的。相对于Druid来说,它更加轻量级 d. Druid连接池在连接管理之外提供了更多的功能,例如SQL防火墙、统计分析、缓存、访问控制等,适用于在数据库访问过程中,需要进行细粒度控制的场景 e. HikariCP则更侧重于性能方面的优化,对各种数据库的兼容性也更好 - BoneCP a. 2015年诞生 b. BoneCP是一款Java语言下的高性能连接池,于2015年由Dominik Gruntz在GitHub上发布。BoneCP具有分布式事务、连接空闲检查、SQL语句跟踪和性能分析、特定类型的连接池等特点。BoneCP连接池适用于大型应用系统和高并发的负载场景 #### 10.3 连接池的使用 https://www.yuque.com/dujubin/java/deecp60imxtzcue7 - Druid的使用: JDBCTest24.java 第一步:引入Druid的jar包 第二步:配置文件 第三步:编写代码,从连接池中获取连接对象 第四步:关闭连接:仍然调用Connection的close()方法,但是这个close()方法并不是真正的关闭连接,只是将连接归还到连接池,让其称为空闲连接对象。这样其他线程可以继续使用该空闲连接。 - HikariCP的使用:JDBCTest26.java 第一步:引入jar包 第二步:编写配置文件 第三步:编写代码,从连接池中获取连接 第四步:关闭连接(调用conn.close(),将连接归还到连接池,连接对象为空闲状态。 完结撒花!!