Review: Java SE 05(JDBC、数据库连接池和DBUtils)
Java SE 05
一、JDBC
1. JDBC概述
- JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范。是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范
- JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而不同的数据库厂商需要实现这套接口,提供数据库驱动jar包,开发者可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类
2. 使用JDBC实现类进行开发的流程
-
添加MySQL驱动jar包到当前项目下
-
注册驱动
作用:将厂商的jar包中的实现类加载到当前类下,比如
com.mysql.jdbc.Driver
中定义了静态代码块当Driver类加载后执行静态代码块中的注册驱动语句从 JDBC3 开始,目前已经普遍使用的版本,可以不用注册驱动而直接使用,Class.forName 这句话可以省略
-
获得连接
使用DriverManager类中getConnection方法来获取连接即获取Connection对象
getConnection方法中需要传入的参数有3个
URL(包括数据库厂商名称、服务器所在IP、端口号、所选数据库、参数信息(可选)),数据库用户名,密码
-
获取语句执行平台(获取Statement接口对象)
通过Connection对象调用createStatement方法来获取Statement对象
Statement对象:代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象
Statement对象中常用方法:
int executeUpdate(String sql)
用于执行insert update delete语句,也支持DDL.返回int类型,代表受影响的行数ResultSet executeQuery(String sql)
用于执行select语句, 返回ResultSet结果集对象注意:sql字符串中写SQL语句,其中字符串使用单引号,语句结尾
;
可以省略 -
处理结果集(只在查询时处理)
只有在进行查询操作executeQuery的时候, 才会处理结果集ResultSet
ResultSet常用方法:
boolean next()
游标指向下一行,还有下一条记录就返回truexxx getXxx( String or int)
重载方法,通过列名或列号(索引从1开始)进行获取数据 -
释放资源
-
需要释放的对象:ResultSet 结果集(非查询,不用释放),Statement 语句,Connection 连接
-
释放原则:先开的后关,后开的先关;ResultSet ==> Statement ==> Connection
释放方法就是调用对应的close方法
-
一般将释放资源的语句放在异常处理的finally代码块中
-
3. JDBC实现增删改查
-
JDBC工具类
-
工具类:如果一个功能经常要用到,建议把这个功能做成一个工具类,可以在不同的地方重用
-
获取Connection和释放资源在增删改查中会重复使用,所以将这两个操作的方法封装为JDBCUtils工具类中的静态方法
获取Connection需要URL、数据库用户名、密码、驱动全类名的字符串(可省)可以将这些字符串设置为工具类中的常量,
若使用低版本的JDBC中还需要将Class.forName加载驱动的操作也封装在工具类中
-
封装JDBCUtils工具类的实例(不含注册驱动的版本)
public class JDBCUtils { //1. 定义字符串常量, 记录获取连接所需要的信息 public static final String URL = "jdbc:mysql://localhost:3306/db_jdbc_test"; public static final String USERNAME = "root"; public static final String PASSWORD = "xxxx"; //2.获取连接的静态方法 public static Connection getConnection() { try { //获取连接对象 Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); //返回连接对象 return conn; } catch (SQLException e) { e.printStackTrace(); return null; } } //关闭资源的方法(DML) public static void close(Connection conn, Statement stmt) { if (conn != null && stmt != null) { try { conn.close(); stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } } //关闭资源的方法(重载方法用于DQL后的释放资源) public static void close(Connection conn, Statement stmt, ResultSet res) { if (res != null) { try { //对ResultSet对象进行关闭 res.close(); } catch (SQLException e) { e.printStackTrace(); } } //直接复用DML的释放资源方法 close(conn, stmt); } }
-
-
DML操作
-
防止插入中文乱码的解决方案
将工具类中URL字符串中指定字符的编解码格式
jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8
-
使用工具类进行插入、删除、更改
public void test() throws SQLException { //1.通过工具类获取连接 Connection connection = JDBCUtils.getConnection(); //2.获取Statement Statement statement = connection.createStatement(); //2.1 编写Sql String sql = "xxx"; //2.2 执行Sql statement.executeUpdate(sql); //3.通过工具类关闭流 JDBCUtils.close(connection,statement); }
-
-
DQL操作
-
使用工具类进行查询操作
public void test() throws SQLException { //1.通过工具类获取连接 Connection connection = JDBCUtils.getConnection(); //2.获取Statement Statement statement = connection.createStatement(); //2.1 编写Sql String sql = "xxx"; //2.2 执行Sql, 获取ResultSet对象 ResultSet res = statement.executeUpdate(sql); //2.3处理结果集 //3.通过工具类关闭流 JDBCUtils.close(connection, statement, res); }
-
4. SQL注入问题
-
问题:用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了原有SQL 真正的意义
拼接后WHERE条件永远为真,相当于没有过滤,查询全部数据,造成密码不正确也能进行查询现象
-
解决:防止用户输入的密码和执行查询的SQL语句进行拼接
5. PreparedStatement接口
-
PreparedStatement接口概述
-
PreparedStatement接口是Statement接口的子接口,继承了Statement中的所有方法
-
PreparedStatement是一个预编译的SQL语句对象
预编译是指SQL 语句被预编译,并存储在 PreparedStatement对象中,然后可以使用此对象多次高效地执行该语句
-
-
PreparedStatement特点
- 预编译可以提高SQL执行的效率
- 可以有效防止SQL注入的问题
- 可以减少编译次数提高数据库性能
- PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数
?
,在执行时可以为?
动态设置参数值
-
获取PreparedStatement对象
通过Connection中的方法
PreparedStatement prepareStatement(String sql)
通过Connection中的方法获取Statement对象的方法
Statement createStatement()
中是空参的,使用Statement对象时才传入SQL参数
指定预编译的 SQL 语句,SQL 语句中使用占位符
?
创建一个语句对象如:
"SELECT * FROM jdbc_user WHERE username=? AND password=?";
-
使用PreparedStatement步骤
-
获取PreparedStatement对象(传入包含动态参数的SQL语句)
-
使用
setXxx(占位符位置,真实的值)
方法设置占位符参数占位符的起始索引是1
-
执行PreparedStatement中处理SQL的方法
PreparedStatement接口中的常用方法同Statement接口,不同是Statement的方法中传参是完整的静态SQL字符串:
int executeUpdate();
执行insert、update、delete语句ResultSet executeQuery();
执行select语句,返回结果集对象ResuletSet -
释放资源(调用PreparedStatement对象中的close方法)
-
-
Statement与PreparedStatement的对比
-
先通过Connection生成对象Statement,Statement对象每调用一次处理SQL的方法,就会将SQL发送给数据库,数据库要先编译再执行;
假如有一万条数据,就会编译一万次
-
通过Connection生成PreparedStatement对象的同时会将SQL语句发送给数据库进行预编译,后面执行多次插入操作,每次只需要调用PreparedStatement中的setXxx方法进行占位符的参数设置和调用处理SQL的方法;
假如有一万条数据,数据库也只是进行一次编译,所以可以减少编译次数,提高效率
-
6. JDBC控制事务
-
可以使用MySQL的命令来操作事务,也可以使用JDBC实现类来操作事务
-
一般使用Connection中的方法实现事务管理
使用步骤:
-
获取连接
-
开启事务
void setAutoCommit(boolean autoCommit)
参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务
-
获取到 PreparedStatement , 执行更新操作
-
正常情况下提交事务
void commit()
-
出现异常回滚事务
void rollback()
-
关闭资源
-
二、数据库连接池和DBUtils
1. 数据库连接池
-
连接池概述
-
作用:实际开发中获得连接或释放资源是非常消耗系统资源的两个过程,为了解决性能的问题,通常采用连接池技术,来共享Connection。这样就不需要每次都创建连接、释放连接了,将这些操作都交给连接池了。
用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。
-
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池。
-
-
DBCP连接池
-
在DBCP包中提供了DataSource接口的实现类,具体是连接池BasicDataSource类
DataSource接口中的常用方法:
Connection getConnection()
-
封装DBCPUtils工具类:
- 定义常量保存数据库连接的相关信息(DRIVERNAME、URL、USERNAME、PASSWORD)
- 创建连接池对象(使用DBCP提供的实现类BasicDataSource类,将该对象定义为静态成员变量)
- 使用静态代码块进行数据库连接的相关信息配置(使用BasicDataSource中的setXxxx方法)
- 封装获取连接的静态方法(使用BasicDataSource类创建的静态成员变量调用getConnection方法)
- 封装释放资源的静态方法(DML、DQL两种close方法重载)
-
使用DBCPUtils工具类:
在获得连接和释放资源时使用DBCPUtils中的方法来实现对数据库的DML、DQL操作
-
-
C3P0连接池
-
C3P0提供的核心工具类, ComboPooledDataSource , 如果想使用连接池,就必须创建该类的对象
-
封装C3P0Utils工具类:
-
创建连接池对象通过使用C3P0对DataSource接口的实现类,将这个对象作为C3P0Utils的静态成员变量
C3P0中的配置信息都存储在配置文件c3p0-config.xml中,可以定义默认配置和指定配置名的配置
在ComboPooledDataSource构造方法中空参为使用XML的默认配置,带参为使用XML中指定配置名
-
封装获取连接的方法(使用ComboPooledDataSource类创建的静态成员变量调用getConnection方法)
-
封装释放资源的方法(DML、DQL两种close方法重载)
-
-
使用C3P0Utils工具类
在获得连接和释放资源时使用C3P0Utils中的方法来实现对数据库的DML、DQL操作
-
-
Druid连接池
-
Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况
-
必要的jar包
-
封装DruidUtils工具类:
-
通过工厂类DruidDataSourceFactory的
createDataSource(Properties p)
方法获取连接池DataSource类型对象-
Druid中的配置信息一般存储在
.properties
文件中,文件名可自定义 -
设置一个静态代码块在DruidUtils工具类加载时创建连接池DataSource类型的对象:
Druid连接池不能够主动加载配置文件 ,需要指定文件,将指定的文件加载到字节输入流对象中传入Properties类型对象的load方法中,传入工厂类
createDataSource(Properties p)
方法中来创建连接池对象
-
-
封装获取连接的方法(使用DataSource类型的静态成员变量调用getConnection方法)
-
封装释放资源的方法(DML、DQL两种close方法重载)
-
-
使用DruidUtils工具类
在获得连接和释放资源时使用DruidUtils中的方法来实现对数据库的DML、DQL操作
-
2. DBUtils工具类
-
DBUtils中的核心功能
DbUtils类,是一个工具类,定义了关闭资源与事务处理相关方法
-
JavaBean组件的概念
- JavaBean就是一个类,开发中通常用于封装数据
- 需要实现序列化接口Serializable
- 提供私有字段
- 提供getter和setter
- 提供空参构造
- JavaBean就是一个类,开发中通常用于封装数据
-
使用DBUtils中的QueryRunner完成增删改
-
创建QueryRunner
自动方式创建需要向QueryRunner构造中传入DataSource类型的数据库连接池对象
手动方式创建需要使用QueryRunner空参构造
-
QueryRunner实现增删改操作主要方法
update(Connection conn, String sql, Object... params)
update(String sql, Object... params)
-
update方法是有重载的方法,当QueryRunner是自动方式创建的不用传Connection对象,
手动方式创建QueryRunner要传入Connection对象,使用连接池工具类调用其中的getConnection方法获取
-
动态SQL中使用
?
作为占位符 -
params是可变长度Object类型的变量(一般传入Object[]类型数组),用来设置占位符上的参数
-
当动态SQL中使用
?
作为占位符的参数只有一个时,不需要创建数组传参,直接在params位置传入这一个参数即可
-
-
QueryRunner实现增删改操作主要流程
- 创建QueryRunner对象(自动或手动)
- 调用QueryRunner对象中的update方法
-
-
使用DBUtils中的QueryRunner完成查询操作
-
创建QueryRunner
-
QueryRunner实现查询操作主要方法
query(Connection con,String sql,handler,Object[] param)
query(String sql, handler ,Object[] param)
query方法的返回值都是泛型,具体的返回值类型,会根据结果集的处理方式,发生变化
其中handler需要的对象类型是ResultSetHandler接口的实现类,ResultSetHandler可以对查询出来的ResultSet结果集进行处理,达到一些业务上的需求,每一种实现类都代表了对查询结果集的一种处理方式
常用的ResultSetHandler实现类:
ArrayHandler 将结果集的第一条数据封装到数组中
ArrayListHandler可以将每条数据先封装到数组中, 再将数组封装到集合中
BeanHandler 将结果集的第一条数据封装到 JavaBean中
BeanListHandler 将结果集的每一条和数据封装到 JavaBean中 再将JavaBean 放到list集合中
MapHandler 将结果集的第一条记录封装到 Map<String,Object>中 key对应的是 列名 value对应的是 列的值
ScalarHandler 用于封装单个的数据
-
QueryRunner实现查询操作主要流程
- 创建QueryRunner对象(自动或手动)
- 调用QueryRunner对象中的query方法
-
3. 数据库批处理
-
数据库批处理概述
- 批处理指的是一次操作中执行多条SQL语句,批处理相比于一次一次执行效率会提高很多
- 批处理操作主要使用了Statement或PreparedStatement中的批处理方法
-
实现数据库批处理
-
mysql 批处理是默认关闭的,所以需要加一个参数才打开mysql 数据库批处理,在url中添加
rewriteBatchedStatements=true
-
批处理主要方法
void addBatch()
将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中,
通过调用方法 executeBatch 可以批量执行此列表中的命令
int[] executeBatch()
每次提交一批命令到数据库中执行,如果所有的命令都成功执行了,
那么返回一个数组,这个数组是说明每条命令所影响的行数
-
实现数据库批处理的主要流程
- 获取Connection对象
- 获取PreparedStatement或Statement对象
- 将SQL添加到批处理列表
- 统一进行批量处理
-
4. MySQL元数据
-
MySQL元数据概述
- 除了表之外的数据都是元数据,包括查询结果信息、数据库和数据表的信息、MySQL服务器信息
- 查看MySQL元数据的常用命令
-
JDBC获取数据库元数据信息
connection 连接对象, 调用
getMetaData()
方法,获取的是DatabaseMetaData 数据库元数据对象调用DatabaseMetaData中的方法获取数据库元数据信息
-
JDBC获取结果集元数据信息
PreparedStatement 预处理对象调用
getMetaData()
, 获取的是ResultSetMetaData , 结果集元数据对象调用ResultSetMetaData中的方法获取结果集元数据信息
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具