实用指南:JDBC以及工具类介绍

news/2026/1/24 22:15:36/文章来源:https://www.cnblogs.com/yangykaifa/p/19527674

JDBC的概述

JDBC(Java Database Connectivity)是Java语言操作关系型数据库的标准化应用程序接口(API),由 Java 官方定义并包含于 java.sql 与 javax.sql 包中。它通过一套统一的接口规范,为Java程序提供了访问各类关系型数据库的标准方式——开发者无需关注不同数据库的底层实现差异,只需遵循JDBC接口进行编程,即可实现对不同数据库的通用操作,有效避免了针对特定数据库编写差异化代码的问题。
作为一套标准化的数据库接口规范,JDBC的核心是定义了Connection(数据库连接)、Statement(SQL执行器)、ResultSet(结果集)等关键接口(及少量辅助类),明确了数据库操作的标准流程与方法。这些接口的具体实现则由数据库厂商提供,即数据库驱动程序——驱动作为Java程序与数据库之间的桥梁,负责将JDBC接口的调用转化为数据库可识别的底层协议(如MySQL的TCP协议),实现具体适配。
数据库驱动本质上是实现了JDBC接口的类库(通常打包为JAR文件),使用时需手动导入对应数据库的驱动包。例如,MySQL的驱动实现类为com.mysql.cj.jdbc.Driver,它实现了JDBC的Driver接口,用于建立应用程序与MySQL数据库的连接。基于JDBC规范与驱动的配合,开发者可便捷地完成执行SQL语句、处理查询结果、管理事务等核心数据库操作。

JDBC 的工作流程

加载并注册数据库驱动

目标:确保 JVM 能够识别并加载指定数据库的驱动程序(Driver),以便后续通过驱动建立与数据库的连接。
原理:数据库厂商提供的驱动类实现了 JDBC 标准接口,程序需将该类加载到内存并自动注册到 DriverManager(驱动管理器)中
两种实现方式:

1.显式加载驱动

java.sql.DriverManager 类提供了静态方法 registerDriver(Driver driver),用于手动注册驱动,需要传入一个具体的驱动实现类实例
创建MySQL驱动实例,显式注册驱动到DriverManager
public class DriverLoad1 {public static void main(String[] args) throws Exception {// 创建MySQL驱动实例Driver driver = new Driver();// 显式注册驱动到DriverManagerDriverManager.registerDriver(driver);// 后续可通过DriverManager获取连接// Connection conn = DriverManager.getConnection(url, user, password);}
}

2.通过反射加载驱动类(触发自动注册)

MySQL 驱动类的内部包含静态代码块,当类被加载时,静态代码块会自动调用 DriverManager.registerDriver() 完成注册,因此只需通过 Class.forName() 反射加载驱动类,即可间接完成注册。
public class DriverLoad2 {public static void main(String[] args) throws Exception {// 反射加载MySQL驱动类,触发静态代码块自动注册Class.forName("com.mysql.cj.jdbc.Driver");// 后续可通过DriverManager获取连接// Connection conn = DriverManager.getConnection(url, user, password);}
}

建立数据库连接

使用驱动管理器 DriverManager 的 getConnection 方法获取连接:DriverManager.getConnection(url, username, password),该方法返回的 Connection 对象代表 Java 与数据库之间的会话
url参数格式说明:jdbc:mysql://localhost:3306/day07
jdbc 代表的主协议,mysql 代表子协议,localhost 是ip地址,3306 是默认的端口号,day07 是数据库名称
当访问本地数据库时,可省略主机和端口信息,简写为:jdbc:mysql:///day07

创建 SQL 执行载体

Connection 接口作为 Java 与数据库交互的桥梁,代表 Java 程序与数据库之间建立的会话连接,该连接使用完毕后必须及时关闭以释放资源。
Connection 接口主要提供两大功能:
  • 创建用于执行 SQL 语句的载体Statement createStatement():创建 Statement 接口实现对象PreparedStatement prepareStatement(String sql):创建 Statement 接口的子接口 PreparedStatement 的实现对象,有效防止 SQL 注入漏洞
  • 事务管理void setAutoCommit(boolean autoCommit):设置事务的自动提交模式 void commit():提交当前事务 void rollback():回滚当前事务

执行 SQL 语句

Statement 接口用于向数据库发送静态 SQL 语句并获取执行结果
executeQuery(String sql):执行查询语句(如SELECT),返回ResultSet对象(包含查询结果);
executeUpdate(String sql):执行更新语句(如INSERT、UPDATE、DELETE),返回受影响的行数(int);
execute(String sql):执行任意 SQL 语句(可执行查询或更新),返回boolean值(true表示有结果集,false表示无结果集);
Statement 的子类 PreparedStatement,预编译 SQL 语句,支持动态参数(通过?占位符),解决了静态 SQL 的局限性,可防止 SQL 注入,执行效率更高(适合重复执行的 SQL)。

处理结果

ResultSet 接口用于封装 SQL 查询结果集,以表格形式存储查询数据,通过遍历该接口可获取查询结果
  • 封装数据内部维护游标,初始位置在第一行数据之前调用 next() 方法使游标下移(返回 true 表示有下一行数据),通过 getXxx(列索引/列名) 方法逐行获取数据(默认仅支持向下移动)
  • 数据获取(根据字段类型调用对应方法)整型(int/bigint):使用getInt()或者getLong()字符串(varchar/char):使用 getString()通用类型:getObject()(需自行强制转换)
  • 获取数据的方法是重载的按列索引:getInt(int index)(索引从1开始)按列名:getInt(String columnName) 通过字段的名称来取值(比较常用)

释放资源

关闭所有数据库相关资源(ResultSet、Statement、Connection),避免资源泄漏(数据库连接是稀缺资源,不关闭会导致连接耗尽)
注意关闭顺序:先开后关(ResultSet → Statement → Connection),且必须在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();}}
}

数据库操作中加载驱动、获取连接、关闭资源等,这些操作的逻辑是通用的,可以进行向上提取

JDBC工具类三版本

1.0版本

/*** JDBC的工具类1.0版本*/
public class JdbcUtil1 {//加载驱动public static void loadDriver() {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}// 获取连接public static Connection getConnection() {//加载驱动loadDriver();//获取连接对象Connection conn = null;try {conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/ssm", "root", "123456");} catch (SQLException e) {e.printStackTrace();}return conn;}/*** 关闭资源,适用查询有结果集* @param conn* @param stmt* @param rs*/public static void close(Connection conn, Statement stmt, ResultSet rs) {if (rs != null) {try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }}if (stmt != null) {try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }}if (conn != null) {try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }}}/*** 关闭资源,适用增删改无结果集* @param conn* @param stmt*/public static void close(Connection conn, Statement stmt) {if (stmt != null) {try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }}if (conn != null) {try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }}}
}

为什么在这个JdbcUtil1工具类中,所有方法都用static修饰?

如果不用static修饰,使用时必须先创建JDBCUtil1的实例:

JDBCUtil1 util = new JdbcUtil1(); // 多余的实例化
Connection conn = util.getConnection();

在 Java 中,static 关键字修饰方法表示该方法是类方法,属于类本身,而非类的某个具体实例,用 static 修饰后,可以直接通过类名调用,无需创建实例,更简洁高效:

Connection conn = JdbcUtil1.getConnection(); // 直接调用,无需new对象

2.0版本

其核心优化在于通过读取properties属性文件管理数据库连接参数而非硬编码,从而方便配置修改并减少代码冗余

/*** JDBC的工具类2.0版本*/
public class JdbcUtil2 {private static final String driverclass;private static final String url;private static final String username;private static final String password;static {//加载属性文件Properties prop = new Properties();InputStream inputStream = JdbcUtil2.class.getResourceAsStream("/db.properties");try {// 加载配置文件prop.load(inputStream);}catch (IOException e){e.printStackTrace();}// 从配置文件获取参数driverclass = prop.getProperty("driver");url = prop.getProperty("url");username = prop.getProperty("user");password = prop.getProperty("password");}/*** 加载驱动*/public static void loadDriver() {try {Class.forName(driverclass);} catch (ClassNotFoundException e) {e.printStackTrace();}}// 获取连接public static Connection getConnection() {//加载驱动loadDriver();//获取连接对象,返回Connection conn = null;try {// 获取到链接conn = DriverManager.getConnection(url, username, password);} catch (SQLException e) {e.printStackTrace();}return conn;}// 关闭资源,适用增删改无结果集public static void close(Connection conn, Statement stmt) {if (stmt != null) {try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }}if (conn != null) {try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }}}// 关闭资源,适用查询有结果集public static void close(Connection conn, Statement stmt, ResultSet rs) {if (rs != null) {try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }}if (stmt != null) {try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }}if (conn != null) {try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }}}
}

该类定义了四个 private static final 修饰的静态成员变量,这些变量由类加载时自动执行的静态代码块初始化,初始化过程为:当前类的类对象从项目的类路径中读取 db.properties 资源文件,并返回一个用于读取该文件内容的 InputStream 输入流对象,Properties 是 Java 中专门用于处理键值对形式配置文件的工具类(能方便地存储和获取配置项),通过调用 Properties 的load(InputStream inStream) 方法,从获取到的输入流中读取属性列表(键和元素对),并将其解析后存储到 prop 对象中,后续通过 getProperty(String key) 用指定的键在此属性列表中搜索属性,获取对应配置值,并赋值给静态变量,这样初始化静态成员变量就完成了。这样就可以通过读取 properties 配置文件获取数据库连接参数(而非硬编码在代码中),方便后期修改数据库配置。

该工具类中还提供了三个核心方法:loadDriver方法通过反射调用Class.forName(driverclass)加载数据库驱动;getConnection方法先调用loadDriver加载驱动,再通过DriverManager.getConnection(url, username, password)获取数据库连接并返回;此外还有两个重载的close方法,分别用于增删改(无结果集)和查询(有结果集)操作后的资源关闭,前者关闭Connection和Statement,后者按ResultSet→Statement→Connection的顺序关闭资源,且每个资源关闭前都会判断非空以避免空指针异常。

3.0版本

简化 Java 程序操作数据库的流程 —— 通过连接池复用数据库连接,避免频繁创建 / 关闭连接的性能损耗

导入坐标依赖

    com.alibabadruid1.2.8
/*** JDBC工具类 3.0 版本* 加入数据库连接池*/
public class JdbcUtil3 {// 连接池对象private static DataSource DATA_SOURCE;static {// 加载属性文件Properties prop = new Properties();InputStream inputStream = JdbcUtil3.class.getResourceAsStream("/druid.properties");try {// 加载配置文件prop.load(inputStream);// 创建连接池对象DATA_SOURCE = DruidDataSourceFactory.createDataSource(prop);} catch (Exception e) {e.printStackTrace();}}/*** 从连接池获取连接*/public static Connection getConnection() {Connection conn = null;try {conn = DATA_SOURCE.getConnection(); // 从连接池拿连接} catch (SQLException e) {e.printStackTrace();}return conn;}/*** 关闭资源(连接归还到池,而非真正关闭)*/public static void close(Connection conn, Statement stmt, ResultSet rs) {if (rs != null) {try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }}if (stmt != null) {try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }}if (conn != null) {try {// 连接池的连接close()是归还,不是关闭conn.close();} catch (SQLException e) {e.printStackTrace();}}}// 重载:无结果集时归还public static void close(Connection conn, Statement stmt) {if (stmt != null) {try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }}if (conn != null) {try {// 连接池的连接close()是归还,不是关闭conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}

这是一个基于Druid连接池的JDBC工具类,其核心逻辑是通过数据库连接池高效管理数据库连接。在类加载时,静态代码块会加载druid.properties配置文件(该文件包含数据库驱动类、连接URL、用户名、密码以及连接池参数如初始连接数、最大活跃连接数等),并利用DruidDataSourceFactory创建连接池对象DARA_SOURCE;提供getConnection()方法从连接池获取数据库连接,而非直接创建新连接,以减少资源消耗;提供两个重载的close()方法,用于关闭Statement、ResultSet并将连接归还给连接池而非真正关闭连接),其中一个处理包含ResultSet的情况,另一个处理无ResultSet的情况,通过这种方式实现连接的复用,提升数据库操作效率。

SQL 注入漏洞

SQL 注入漏洞分析

当使用字符串拼接方式构造SQL语句时:String sql = "select * from t_user where username = '"+username+"' and password ='"+password+"'";
攻击者可通过特殊输入绕过验证:
输入用户名为 aaa'or'1=1(密码任意) 最终SQL语句变为: String sql = "select * from t_user where username = 'aaa'or'1=1' and password = 'sfsdfsds";
输入用户名为 aaa'-- '(密码任意) 最终SQL语句变为:String sql = "select * from t_user where username = 'aaa'‐‐ '' and password = 'sfsdfsdfs";
本质是拼接SQL语句,最终 SQL 会返回数据库中所有用户数据,攻击者无需正确密码即可登录

解决方案

“参数化查询”是一种旨在防御SQL注入的安全机制,其核心思想是通过严格分离SQL语句的结构与参数数据,确保用户输入仅作为“数据”参与数据库操作,而非被解析为SQL代码的一部分。
在Java语言中,PreparedStatement 接口( Statement 的子接口)是遵循JDBC规范、实现参数化查询机制的标准工具,也是Java开发者防御SQL注入的首选方案。其实现逻辑与核心功能如下:
  1. 基于“预编译+参数占位符”的结构锁定
PreparedStatement 通过以下流程实现SQL结构与参数的分离:
  • 使用 ? 作为参数占位符,替代SQL语句中需要动态传入的参数
  • 调用 Connection.prepareStatement(String sql) 方法,将包含占位符的SQL模板发送至数据库服务器进行预编译,生成固定的执行计划,此时SQL语句的逻辑结构已被永久锁定,无法被后续传入的参数修改;
  • 后续通过 setXxx() 系列方法(如setInt()、setString()、setObject()等)向占位符传入具体参数值,这些参数仅作为“数据”填充至预设位置,不会被数据库引擎解析为SQL代码。
  1. setXxx() 方法内容
setXxx() 系列方法是参数化查询机制在代码层面的关键实现,通过双重机制强化安全性:
  • 强制类型匹配:根据方法名(如setInt()对应整数类型、setString()对应字符串类型)对传入参数进行类型校验,确保参数类型与SQL语句中对应字段的类型要求一致,从源头避免因类型不匹配导致的注入风险;
  • 自动转义特殊字符:对于字符串等可能包含特殊符号的参数类型,数据库驱动会自动对单引号、分号、注释符等SQL注入常用字符进行转义处理(如将单引号转换为数据库可识别的转义形式),确保这些字符仅作为数据的一部分被处理,而非用于篡改SQL结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1211321.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2026 年,macbook air 2015 升级注意事项

最近看到 macbook air 2015 可以升级 m.2硬盘,随买了 SN570 ,容量 1T,为了升级耗费了好多天,试了好多坑,现在把这几个坑记录下 1. 制作 macos 按照 U盘1.1 容量大于16G的好U盘 1.2 关闭 WIFI 1.3 使用磁盘工具抹除…

大数据领域Kafka的数据备份与恢复

知识金字塔构建者:Kafka数据备份与恢复的底层逻辑与实践指南 1. 引入与连接:当Kafka集群崩溃时,我们该如何拯救数据? 1.1 一个让工程师冒冷汗的场景 想象一下:你是某电商公司的大数据工程师,正值618大促高峰…

知网AI率降到10%以下?这4款降AI工具亲测有效

知网AI率降到10%以下?这4款降AI工具亲测有效 TL;DR 太长不看 知网AI率降到10%以下不是梦,关键是选对工具。实测4款有效的降AI工具:比话降AI专攻知网检测(承诺15%以下,不达标退款),嘎嘎降AI性价比…

DeepSeek写的论文怎么降AI?亲测从90%降到5%的完整攻略

DeepSeek写的论文怎么降AI?亲测从90%降到5%的完整攻略 TL;DR 太长不看 DeepSeek写的论文AI率通常在70%-90%,仅靠DeepSeek自己改写只能降20%-30%,必须配合专业工具。亲测最有效的方案:先用DeepSeek粗改一遍(把长句拆短、…

知网AIGC检测实测:比话和学术猹谁能降到15%以下

知网AIGC检测实测&#xff1a;比话和学术猹谁能降到15%以下 TL;DR&#xff1a;实测对比比话降AI和学术猹两款8元/千字的工具。学术猹是有道出品&#xff0c;平均AI率可降至14.3%&#xff0c;文科论文表现出色&#xff1b;比话降AI专攻知网&#xff0c;承诺AI率<15%否则退款&…

计算机Java毕设实战-基于Java+springboot的校园编程俱乐部管理系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

详细介绍:NoSQL 数据库和内存数据库 - MongoDB简单了解

详细介绍:NoSQL 数据库和内存数据库 - MongoDB简单了解2026-01-24 22:11 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; …

【课程设计/毕业设计】基于springboot的校园编程俱乐部管理系统【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

自主搭建AI系统:全流程硬件配置与实施要点解析

人工智能技术于各行各业越来越深入地应用着&#xff0c;越来越多的组织开始思量着自主去搭建AI系统。这样的部署方式能够更优地满足数据安全、业务定制以及持续优化的需求&#xff0c;然而与此同时也给技术团队提出了更高的要求。一个完整的AI系统搭建牵涉到硬件选型、软件部署…

组织本地化部署AI系统需系统性规划与专业技术知识

随着人工智能技术迅猛发展&#xff0c;越来越多组织着手考虑于本地环境里部署、搭建AI系统。这般本地化地部署&#xff0c;不但能够更为妥善地契合数据安全以及隐私保护的要求&#xff0c;而且还能够依照具体业务需求予以深度定制。然而&#xff0c;AI系统搭建属于一个牵涉硬件…

WSL2迁移D盘+修改默认用户

WSL2迁移D盘+修改默认用户1. 迁移 WSL2 到 D 盘查看 WSL 发行版wsl --list --verbose关闭 WSLwsl --shutdown导出镜像到 D 盘wsl --export Ubuntu-22.04 D:\WSL\Ubuntu.tar注销 C 盘旧镜像wsl --unregister Ubuntu-22.…

42.9k Star!Windows 最好用的网速监控工具,支持任务栏显示

Windows 自带的任务管理器能看网速&#xff0c;但得专门打开一个窗口&#xff1b;第三方工具要么太丑、要么太重、要么全是广告。 TrafficMonitor 是一款 Windows 桌面悬浮窗软件&#xff1a;实时显示网速、CPU 和内存占用率&#xff0c;支持嵌入任务栏、更换皮肤、硬件温度监…

Java计算机毕设之基于springboot的高校计算机编程俱乐部管理系统(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

技术团队强的商城源码团队核心优势

结合单商户零售商城场景与安全保障需求&#xff0c;技术团队强的商城源码团队优势集中在源码掌控、安全防护、架构适配、高效迭代四大维度&#xff0c;可直接转化为系统竞争力与风险抵御能力&#xff0c;具体如下&#xff1a; 一、源码级深度管控&#xff0c;筑牢安全根基 全…

Elasticsearch 基本使用

版本以 Elasticsearch 7.x 为主(目前最常用) 一、依赖(Maven)<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifact…

AI如何做一部视频

AI 如何做一部视频(实战记录:年会祝福片) 0. 概要(TL;DR) 这篇笔记记录一次「用 AI 快速做一支团队年会祝福视频」的实战过程:从需求澄清 → 剧本/分镜 → 角色与场景图生成 → 智能多帧生成视频 → 锁定片段迭代…

【计算机毕业设计案例】基于SpringBoot+Vue的小说阅读平台基于springboot的小说阅读平台(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【计算机毕业设计案例】基于springboot的游泳馆管理系统营销活动(如会员日折扣、组团优惠)(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【计算机毕业设计案例】基于springboot的智能药箱系统,药品分类、药品咨询(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【计算机毕业设计案例】基于springboot的自行车分享平台车辆监控、租赁流程自动化(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…