当前位置: 首页 > news >正文

JDBC 工具类 1.0→3.0 进化史:从手写连接到企业级连接池

首先让我们了解一下什么是JDBC?

🎯 JDBC是Java 操作数据库的一套标准接口 / 规则

它是 Java 自带的一套规范作用:让 Java 程序能连接数据库、执行 SQL、获取结果本质:一套接口(Connection、Statement、ResultSet)数据库厂商(MySQL/Oracle/SQL Server)提供实现类(就是驱动包 jar)

接下来看一下最基础的使用JDBC操作数据库进行“查询”的代码

package JDBCUtilversion1;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;//最初始的查询类,没有任何工具类的封装
public class JdbcDemo {public static void main(String[] args) {Connection conn = null;Statement stmt = null;ResultSet rs = null;try {//把重复性的代码需要向上提取,打包成工具类,只需要写一次// 1.加载驱动Class.forName("com.mysql.jdbc.Driver");//8.0的版本是("com.mysql.cj.jdbc.Driver")// 2.获取连接(改变配置文件去提取这个连接Demo)// 添加 useSSL=false (解决时区警告) 与 characterEncoding=utf8String url = "jdbc:mysql:///jdbcdemo?useSSL=false&characterEncoding=utf8&serverTimezone=UTC";String user = "root";String password = "2020";conn = DriverManager.getConnection(url, user, password);// 3.编写SQLString sql = "SELECT * FROM t_user";// 4.获取执行SQL的对象 Statementstmt = conn.createStatement();// 5.执行查询,得到结果集rs = stmt.executeQuery(sql);//stmt.executeUpdate(sql);   更新操作// 6.遍历ResultSet  为什么除查询出操作不用遍历,只更改行号// 封装实体类遍历while (rs.next()) {int id = rs.getInt("id");String username = rs.getString("username");String pwd = rs.getString("password");String email = rs.getString("email");System.out.println(id + "\t" + username + "\t" + pwd + "\t" + email);}} catch (Exception e) {e.printStackTrace();} finally {// 7.释放资源(开启顺序和释放顺序相反)try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}}}
}

我们可以发现这段代码就是 JDBC 最标准的 7 步流程:


// 1. 加载驱动(告诉Java要用MySQL数据库)
Class.forName("com.mysql.jdbc.Driver");// 2. 获取连接(和数据库建立连接通道)
conn = DriverManager.getConnection(url, user, password);// 3. 写SQL语句
String sql = "SELECT * FROM t_user";// 4. 获取执行SQL的对象
stmt = conn.createStatement();// 5. 执行SQL,得到结果集
rs = stmt.executeQuery(sql);// 6. 遍历结果(把查到的数据打印出来)
while (rs.next()) {System.out.println(id + "\t" + username + ...);
}// 7. 释放资源(关闭连接)
rs.close();
stmt.close();
conn.close();

但是使用这种方式操作数据库存在很多缺点:

1. 重复代码超级多,写 10 次累死人

你每写一个增删改查,都要写:

  • 加载驱动
  • 获取连接
  • 定义 URL、用户名、密码
  • 关闭资源
  • 处理异常

写一次还行,写 100 次要疯!

2. 数据库配置写死在代码里(硬编码)

String url = "jdbc:mysql:///jdbcdemo";
String user = "root";
String password = "2020";

如果密码改了、数据库地址改了你要去所有 Java 文件里一个个改!

这在企业里是绝对禁止的!

3. 每次都新建连接,用完就销毁,性能极差

  • 建立连接 → 耗时
  • 销毁连接 → 耗时
  • 高并发下 → 服务器直接崩掉

就像你每写一个字,就开一次门,关一次门!

4. 关闭资源容易写错、漏写

你必须手动写:

rs.close();
stmt.close();
conn.close();

一旦漏写,内存泄漏、数据库崩溃!

5. 没有任何扩展性

  • 没有监控
  • 没有超时控制
  • 没有最大连接数
  • 没有安全控制

所以!才出现了三个版本的JDBC工具类!

####1.0 版本:解决重复代码* 把固定代码提取出来
* 只写一次连接
* 只写一次关闭
* 所有类直接调用**解决:重复代码问题**
####2.0 版本:解决配置写死
* 把配置放到 db.properties
* 改配置不用改 Java 代码
* 更安全、更灵活**解决:硬编码问题**
####3.0 版本:解决性能问题(连接池)* 使用 Druid 连接池
* 连接复用
* 不用频繁创建 / 销毁
* 性能提升 10~100 倍
* 企业标准用法**解决:性能极低问题**

所以接下来通过代码演示,给大家看一下三个版本的JDBC工具类的区别!!!(这里先初步讲解三个版本的具体区别,最后附上代码)

一、首先创建如下目录结构的普通java项目

image

这是一个纯 Java 项目(非 Maven/Gradle),用来学习和练习 JDBC 数据库操作。

JDBCLearning01/
├─ lib/                  # 第三方依赖包
│  ├─ druid-1.1.10.jar   # Druid 连接池核心包
│  └─ mysql-connector-java-5.1.49.jar  # MySQL 驱动包
├─ out/                  # IDEA 编译后的 class 文件输出目录
└─ src/                  # 源码根目录├─ JDBCUtilversion1/  # 【1.0 版:原生 JDBC 工具类】│  ├─ JdbcDelete│  ├─ JdbcDemo│  ├─ JdbcInsert│  ├─ JdbcUpdate│  └─ JDBCUtils.java├─ JDBCUtilversion2/  # 【2.0 版:配置文件版工具类】│  ├─ db.properties│  └─ JdbcUtils2.java├─ JDBCUtilversion3/  # 【3.0 版:Druid 连接池工具类】│  ├─ druid.properties│  ├─ JdbcTest3.java│  └─ JdbcUtils3.java├─ JdbcTest2.java     # SQL 注入/防注入测试类└─ JdbcTransactionDemo.java  # 事务管理测试类

二、项目整体目标

这是一个JDBC 从入门到进阶的学习项目,核心目标是:

  • 掌握「原生 JDBC」的基础用法

  • 理解「配置文件解耦」的好处

  • 学会「Druid 连接池」的企业级用法

  • 掌握 SQL 注入、事务管理等 JDBC 核心知识点

三、三个版本工具类的对比(核心重点)

这三个版本是逐步迭代、功能越来越强的,我帮你拆解清楚它们的区别、组成和作用。

📌 1.0 版本:JDBCUtilversion1

  • 核心特点:硬编码的原生 JDBC 工具类

  • 组成:JDBCUtils.java + 几个 CRUD 测试类

关键代码:

private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql:///jdbcdemo";
private static final String USER = "root";
private static final String PASSWORD = "2020";
  • 作用:

    • 封装了 getConnection() 和 close() 方法,避免重复写连接 / 关闭代码

    • 纯手动加载驱动、获取连接,完全理解 JDBC 底层流程

  • 缺点:配置写死在代码里,改配置要改源码;每次都是新建连接,性能差

📌2.0 版本:JDBCUtilversion2

  • 核心特点:读取配置文件的 JDBC 工具类

  • 组成:JdbcUtils2.java + db.properties

关键代码:

// 读取 db.properties 配置文件
Properties pro = new Properties();
InputStream in = JDBCUtils2.class.getResourceAsStream("/db.properties");
pro.load(in);
driverClass = pro.getProperty("driverClass");
  • 作用:

    • 把数据库配置(驱动、URL、账号密码)从代码中剥离,放到 db.properties 文件里

    • 解耦了代码和配置,修改配置不用改 Java 代码,直接改配置文件即可

  • 和 1.0 的区别:解决了硬编码问题,但还是没有连接池,性能和 1.0 一样

📌 3.0 版本:JDBCUtilversion3

  • 核心特点:Druid 连接池工具类(企业级标准用法)

  • 组成:JdbcUtils3.java + druid.properties + Druid 连接池包

关键代码:

// 初始化 Druid 连接池
Properties pro = new Properties();
InputStream in = JdbcUtils3.class.getResourceAsStream("/druid.properties");
pro.load(in);
DATA_SOURCE = DruidDataSourceFactory.createDataSource(pro);
  • 作用:

    • 引入了 数据库连接池:提前创建好一批连接放在池子里,用的时候直接拿,用完归还,不用频繁创建 / 销毁连接,性能大幅提升

    • 支持连接池配置(初始连接数、最大连接数、超时时间等)

    • 自带防 SQL 注入、连接监控等高级功能

  • 和前两个版本的区别:从「单次新建连接」升级为「连接池复用」,是实际开发中最常用的版本

四、其他关键文件的作用

文件 作用
lib/ 下的两个 jar 包 mysql-connector-java 是 MySQL 驱动,让 Java 能和数据库通信;druid 是连接池核心包
JdbcTest2.java 测试 SQL 注入漏洞和防注入(PreparedStatement 的使用)
JdbcTest3.java 测试 Druid 连接池的 CRUD 操作
JdbcTransactionDemo.java 测试 JDBC 事务管理(提交、回滚)

五、一句话总结三个版本的迭代

1.0:能跑就行,但是硬编码、性能差
2.0:解耦配置,但是还是没有连接池
3.0:企业级用法,配置文件 + 连接池,性能和可维护性拉满

六、代码示例

目录结构

image

在网上下载两个jar包,下载之后复制到lib文件夹下(lib文件夹需要自己创建)---选中jar包,右击 jar → Add as Library

这里简单介绍一下每个类是做什么的

**JDBCUtilversion1文件夹 **

  • JdbcDemo是最基础使用JDBC的步骤来进行查询数据库内容---没做任何提取

  • JDBCUtils是JDBC 1.0 版本的工具类,主要对 JDBC 操作中的重复代码进行封装:包括数据库固定配置、驱动加载、获取连接、以及两种关闭资源的方法,让代码不再冗余,实现一次编写、到处调用。

  • JdbcDelete、JdbcInsert、JdbcUpdate这三个类都是调用JDBCUtiles工具类的方法,不再写重复的代码,实现对数据库中表的内容的删除、插入、修改操作

**JDBCUtilversion2文件夹下面 **

  • db.properties是数据库配置文件,用来存数据库连接的四要素---driverClass、url、mysql的用户名和密码

  • JdbcUtils2是从 db.properties 读取配置,对 JDBC 操作中的重复代码进行封装:包括驱动加载、获取连接、以及两种关闭资源的方法,

如果想写增删改查的功能,直接调用JdbcUtils2里面的方法即可。

**JDBCUtilversion3文件夹下面 **

  • druid.properties是 Druid 连接池的配置文件,和 2.0 版本的 db.properties 作用类似,但专门给 Druid 用。把数据库连接信息(驱动、URL、账号密码)和连接池参数(初始连接数、最大连接数等)从 Java 代码中抽离出来。让 JdbcUtils3 可以通过DruidDataSourceFactory.createDataSource(pro) 自动创建连接池。

  • JdbcUtils3.java是 3.0 版本的 JDBC 工具类,读取 druid.properties 配置文件,初始化 Druid 连接池;对外提供 getConnection() 方法,从连接池获取连接,而不是每次新建

  • 提供 close() 方法,把连接归还到连接池,而不是直接销毁;完全替代了 1.0/2.0 版本里的 DriverManager

  • JdbcTest3是一个 Druid 连接池的入门测试类,用来验证连接池是否正常工作。

JDBCUtilversion1.JdbcDemo

package JDBCUtilversion1;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;//最初始的查询类,没有任何工具类的封装
public class JdbcDemo {public static void main(String[] args) {Connection conn = null;Statement stmt = null;ResultSet rs = null;try {//把重复性的代码需要向上提取,打包成工具类,只需要写一次// 1.加载驱动Class.forName("com.mysql.jdbc.Driver");//8.0的版本是("com.mysql.cj.jdbc.Driver")// 2.获取连接(改变配置文件去提取这个连接Demo)// 添加 useSSL=false (解决时区警告) 与 characterEncoding=utf8String url = "jdbc:mysql:///jdbcdemo?useSSL=false&characterEncoding=utf8&serverTimezone=UTC";String user = "root";String password = "2020";conn = DriverManager.getConnection(url, user, password);// 3.编写SQLString sql = "SELECT * FROM t_user";// 4.获取执行SQL的对象 Statementstmt = conn.createStatement();// 5.执行查询,得到结果集rs = stmt.executeQuery(sql);//stmt.executeUpdate(sql);   更新操作// 6.遍历ResultSet  为什么除查询出操作不用遍历,只更改行号// 封装实体类遍历while (rs.next()) {int id = rs.getInt("id");String username = rs.getString("username");String pwd = rs.getString("password");String email = rs.getString("email");System.out.println(id + "\t" + username + "\t" + pwd + "\t" + email);}} catch (Exception e) {e.printStackTrace();} finally {// 7.释放资源(开启顺序和释放顺序相反)try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}}}
}

JDBCUtilversion1.JdbcDelete

package JDBCUtilversion1;import java.sql.Connection;
import java.sql.Statement;public class JdbcDelete {public static void main(String[] args) {Connection conn = null;Statement stmt = null;try {conn = JDBCUtils.getConnection();stmt = conn.createStatement();//pstmt=conn.prepareStatement// 想删谁改这里String deleteName = "ccc";String sql = "DELETE FROM t_user WHERE username='"+deleteName+"'";int rows = stmt.executeUpdate(sql);System.out.println("删除成功!影响行数:" + rows);System.out.println("删除的用户:" + deleteName);} catch (Exception e) {e.printStackTrace();} finally {JDBCUtils.close(stmt, conn);}}
}

JDNCUtilversion1.Insert

package JDBCUtilversion1;import java.sql.Connection;
import java.sql.Statement;public class JdbcInsert {public static void main(String[] args) {Connection conn = null;Statement stmt = null;try {// 从工具类获取连接!!!conn = JDBCUtils.getConnection();stmt = conn.createStatement();// 要插入的数据String username = "ddd";String pwd = "666";String email = "ddd@163.com";String sql = "INSERT INTO t_user(username,password,email) VALUES('"+username+"','"+pwd+"','"+email+"')";int rows = stmt.executeUpdate(sql);System.out.println("插入成功!影响行数:" + rows);System.out.println("插入的数据:");System.out.println("用户名:" + username);System.out.println("密码:" + pwd);System.out.println("邮箱:" + email);} catch (Exception e) {e.printStackTrace();} finally {// 工具类关闭资源!!!JDBCUtils.close(stmt, conn);}}
}

JDNCUtilversion1.Update

package JDBCUtilversion1;import java.sql.Connection;
import java.sql.Statement;public class JdbcUpdate {public static void main(String[] args) {Connection conn = null;Statement stmt = null;try {conn = JDBCUtils.getConnection();stmt = conn.createStatement();// 要修改的用户和新密码String username = "aaa";String newPwd = "888888";String sql = "UPDATE t_user SET password='"+newPwd+"' WHERE username='"+username+"'";int rows = stmt.executeUpdate(sql);System.out.println("修改成功!影响行数:" + rows);System.out.println("用户:" + username + " 的密码已改为:" + newPwd);} catch (Exception e) {e.printStackTrace();} finally {JDBCUtils.close(stmt, conn);}}
}

JDBCUtils

package JDBCUtilversion1;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;//这是JDBC1.0版本的工具类,对于固定配置和  (加载驱动、获取链接、两种关闭资源)进行封装public class JDBCUtils {// 固定配置(你只用改这里一次,所有类都生效)private static final String DRIVER = "com.mysql.jdbc.Driver";private static final String URL = "jdbc:mysql:///jdbcdemo?useSSL=false&characterEncoding=utf8&serverTimezone=UTC";private static final String USER = "root";private static final String PASSWORD = "2020";// 1. 静态代码块:驱动只加载一次static {try {Class.forName(DRIVER);} catch (Exception e) {e.printStackTrace();}}// 2. 获取连接public static Connection getConnection() {try {return DriverManager.getConnection(URL, USER, PASSWORD);} catch (Exception e) {e.printStackTrace();return null;}}// 3. 关闭资源(增删改)==》方法里面有两个对象public static void close(Statement stmt, Connection conn) {close(null, stmt, conn);}// 4. 关闭资源(查询)===>需要返回结果集,方法里面有三个对象public static void close(ResultSet rs, Statement stmt, Connection conn) {try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}}
}

JDBCUtilversion2.JdbcUtils2

package JDBCUtilversion2;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
import java.io.InputStream;public class JdbcUtils2 {private static String driverClass;private static String url;private static String username;private static String password;static {try {// 读取配置文件Properties pro = new Properties();InputStream in = JdbcUtils2.class.getResourceAsStream("/db.properties");pro.load(in);driverClass = pro.getProperty("driverClass");url = pro.getProperty("url");username = pro.getProperty("username");password = pro.getProperty("password");Class.forName(driverClass);} catch (Exception e) {e.printStackTrace();}}public static Connection getConnection() {try {return DriverManager.getConnection(url, username, password);} catch (Exception e) {e.printStackTrace();return null;}}public static void close(Statement stmt, Connection conn) {close(null, stmt, conn);}public static void close(ResultSet rs, Statement stmt, Connection conn) {try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}}}

JDBCUtilversion2文件夹下的db.properties

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///jdbcdemo?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
username=root
password=2020

JDBCUtilversion3.JdbcTest3

package JDBCUtilversion3;import JDBCUtilversion2.JdbcUtils2;
import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;//JDBC的工具类1.0版本
//JDBC的工具类2.0版本,编写properties属性文件,程序可以读取属性文件
//JDBC的工具类的3.0版本,加入连接池对象//这是JDBC工具类的3.0版本---数据库连接池工具类
public class JdbcUtils3{private static DataSource DATA_SOURCE;static {try {Properties pro = new Properties();InputStream inputStream = JdbcUtils2.class.getResourceAsStream("/JDBCUtilversion3/druid.properties");if (inputStream == null) {throw new RuntimeException("找不到 druid.properties 配置文件!!!");}pro.load(inputStream);DATA_SOURCE = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {throw new RuntimeException("Druid 连接池初始化失败", e);}}public static Connection getConnection() {try {return DATA_SOURCE.getConnection();} catch (SQLException e) {throw new RuntimeException("获取连接失败", e);}}public static void close(Connection conn, Statement stmt, ResultSet rs) {try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (SQLException e) {e.printStackTrace();}}public static void close(Connection conn, Statement stmt) {close(conn, stmt, null);}
}

JDBCUtilversion3.JdbcUtils3

package JDBCUtilversion3;import JDBCUtilversion2.JdbcUtils2;
import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;//JDBC的工具类1.0版本
//JDBC的工具类2.0版本,编写properties属性文件,程序可以读取属性文件
//JDBC的工具类的3.0版本,加入连接池对象//这是JDBC工具类的3.0版本---数据库连接池工具类
public class JdbcUtils3{private static DataSource DATA_SOURCE;static {try {Properties pro = new Properties();InputStream inputStream = JdbcUtils2.class.getResourceAsStream("/JDBCUtilversion3/druid.properties");if (inputStream == null) {throw new RuntimeException("找不到 druid.properties 配置文件!!!");}pro.load(inputStream);DATA_SOURCE = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {throw new RuntimeException("Druid 连接池初始化失败", e);}}public static Connection getConnection() {try {return DATA_SOURCE.getConnection();} catch (SQLException e) {throw new RuntimeException("获取连接失败", e);}}public static void close(Connection conn, Statement stmt, ResultSet rs) {try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (SQLException e) {e.printStackTrace();}}public static void close(Connection conn, Statement stmt) {close(conn, stmt, null);}
}

JDBCUtilversion3文件夹下的druid.properties

# 数据库连接配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo?useSSL=false&serverTimezone=UTC
username=root
password=2020# 连接池配置
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3
http://www.jsqmd.com/news/668196/

相关文章:

  • 我在互联网造文物?“赛博做旧”踩坑记录 - l
  • 崩坏星穹铁道三月七助手:解放双手的终极游戏效率伙伴
  • CSAPP datalab通关秘籍:手把手教你用位运算实现那些‘奇葩’函数(附完整代码与避坑指南)
  • 头歌(educoder)实战解析:从零到一,手撕K-Means聚类算法
  • 简易在线考试系统 - 结对编程项目文档
  • Token消耗激增的根源及系统性优化方案:用户消耗远超购买量
  • 【PolarCTF】x64
  • FastGPT连接OneAPI实战:如何用一套密钥管理多个大模型(通义千问、ChatGLM等)
  • 2026青岛成人高考机构排行榜:Top5深度测评,帮你避开选机构的“坑” - 商业科技观察
  • 3K 行代码造一个越用越聪明的 AI Agent:GenericAgent 登顶 GitHub Trending
  • 用FFmpeg无损剪辑H.264视频翻车实录:从‘-c copy’报错到成功导出MP4的完整避坑指南
  • Python在图片上画圆形:从入门到实战
  • 3步恢复Windows 11 LTSC微软商店:完整应用生态一键安装指南
  • 【Linux从入门到精通】第6篇:管道符、重定向与通配符——命令行效率的核心秘诀
  • Windows服务器运维:如何用mstsc命令和.rdp配置文件打造你的专属远程桌面管理库
  • 【传播模型】CoVeni计算并可视化了病毒附Matlab代码
  • 别光会binwalk了!CTF MISC实战中这5个冷门但好用的文件分析工具,帮你快速定位flag
  • 三步搞定Windows ADB驱动安装:告别繁琐配置,专注Android开发
  • 阿里云盘的FatalError
  • Win11Debloat:三步彻底清理Windows系统,让电脑重获新生
  • 【数字信号调制】自适应调制解调通信系统误码率仿真【含Matlab源码 15364期】
  • LangGraph 并行执行优化:如何提升多智能体任务处理效率?
  • 告别Tomcat:Spring Boot应用改造为纯War包,适配宝兰德等商用中间件全指南
  • Python在图片上画多边形:从简单轮廓到复杂区域标注
  • **发散创新:用Python实现因果推理在推荐系统中的落地应用**在当今数据
  • 【AI面试八股文 Vol.1.1 | 专题4:Conditional Edge】Conditional Edge:动态路由分支逻辑实现
  • SolidWorks参数化设计避坑指南:为什么你的VBA宏跑一次就报错?
  • 家庭网络总断网?可能是你家的路由器接错了!用环路检测功能快速排查
  • Unity Magica Cloth:从入门到精通,打造次世代角色动态服饰
  • 别再只用MD5了!聊聊PBKDF2如何用‘盐’和‘慢炖’保护你的用户密码