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

Java JDBC 封装:从原生写法到工具类封装 + 增删改查

在 Java 操作数据库的过程中原生 JDBC 代码存在大量重复逻辑加载驱动、获取连接、释放资源…… 这些代码在每个业务中都要写一遍不仅繁琐还容易出错。本文是个人的一些学习笔记主要内容如下原生 JDBC 写法与封装后写法对比配置文件 工具类封装增删改查 4 个完整测试案例项目结构与代码规范说明一、项目结构说明当前的项目结构如下所有代码均放在com.qcby包下配置文件放在resources目录src ├── main │ ├── java │ │ └── com.qcby │ │ ├── JDBCUtils.java // 封装好的工具类 │ │ ├── TestJDBC.java // 原生JDBC查询案例封装前 │ │ ├── TestJDBCUtils.java // 封装后查询案例 │ │ ├── TestUpdate.java // 封装后增删改案例 │ └── resources │ └── db.properties // 数据库配置文件二、封装前原生 JDBC 写法以查询为例1. 原生代码痛点硬编码数据库连接信息URL、账号、密码修改时需要改代码每次都要手动写加载驱动、获取连接、释放资源的重复代码资源关闭操作分散容易遗漏导致连接泄漏2. 原生查询案例代码TestJDBC.javapackage com.qcby; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class TestJDBC { public static void main(String[] args) throws Exception { // 1. 加载驱动硬编码驱动类路径 Class.forName(com.mysql.cj.jdbc.Driver); // 2. 获取连接硬编码数据库连接信息 String url jdbc:mysql:///jdbcdemo?serverTimezoneUTCuseSSLfalse; String user root; String password Zhen777; Connection conn DriverManager.getConnection(url, user, password); // 3. 获取执行SQL的对象 Statement stmt conn.createStatement(); // 4. 执行查询SQL String sql select * from t_user; ResultSet rs stmt.executeQuery(sql); // 5. 遍历结果集 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); } // 6. 手动释放所有资源顺序结果集→Statement→连接 rs.close(); stmt.close(); conn.close(); } }三、封装配置文件 JDBC 工具类1. 数据库配置文件db.properties放在src/main/resources目录下统一管理数据库连接信息避免硬编码properties# 驱动类路径MySQL8.0用cj包 driverClasscom.mysql.cj.jdbc.Driver # 数据库连接URL必须加时区配置 urljdbc:mysql:///jdbcdemo?serverTimezoneUTCuseSSLfalse # 数据库账号 usernameroot # 数据库密码修改为你自己的 passwordZhen7772. JDBC 工具类JDBCUtils.java封装加载驱动、获取连接、释放资源的通用逻辑一次编写到处使用package com.qcby; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /** * JDBC工具类封装通用的数据库操作逻辑 * 功能1. 读取配置文件 2. 加载驱动 3. 获取连接 4. 释放资源 */ public class JDBCUtils { // 配置文件对象静态加载一次 private static Properties props new Properties(); // 静态代码块类加载时自动执行只执行一次 static { try { // 读取resources下的db.properties配置文件 props.load(JDBCUtils.class.getClassLoader().getResourceAsStream(db.properties)); // 加载驱动从配置文件读取驱动类路径 Class.forName(props.getProperty(driverClass)); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(JDBC工具类初始化失败请检查配置文件, e); } } /** * 获取数据库连接 * return Connection 数据库连接对象 */ public static Connection getConnection() { try { return DriverManager.getConnection( props.getProperty(url), props.getProperty(username), props.getProperty(password) ); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 释放资源查询场景关闭ResultSet、Statement、Connection * param conn 数据库连接对象 * param stmt Statement对象 * param rs 结果集对象 */ 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 (Exception e) { e.printStackTrace(); } } /** * 释放资源增删改场景关闭Statement、Connection无需关闭ResultSet * param conn 数据库连接对象 * param stmt Statement对象 */ public static void close(Connection conn, Statement stmt) { close(conn, stmt, null); } }四、封装后增删改查1. 查询案例TestJDBCUtils.java使用工具类完成查询代码大幅简化只关注业务 SQLpackage com.qcby; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; public class TestJDBCUtils { public static void main(String[] args) { Connection conn null; Statement stmt null; ResultSet rs null; try { // 1. 从工具类获取连接一行代码搞定 conn JDBCUtils.getConnection(); // 2. 获取执行SQL的对象 stmt conn.createStatement(); // 3. 编写并执行查询SQL String sql select * from t_user; rs stmt.executeQuery(sql); // 4. 遍历结果集并输出 while (rs.next()) { System.out.println( rs.getInt(id) \t rs.getString(username) \t rs.getString(password) \t rs.getString(email) ); } } catch (Exception e) { e.printStackTrace(); } finally { // 5. 释放所有资源调用工具类方法 JDBCUtils.close(conn, stmt, rs); } } }2. 新增案例TestUpdate.java 中 insert 部分package com.qcby; import java.sql.Connection; import java.sql.Statement; public class TestUpdate { public static void main(String[] args) { Connection conn null; Statement stmt null; try { // 1. 获取连接 conn JDBCUtils.getConnection(); // 2. 获取执行对象 stmt conn.createStatement(); // 3. 编写新增SQL String sql insert into t_user values(null,封装测试,666,testqq.com); // 4. 执行增删改SQLexecuteUpdate返回影响行数 int rows stmt.executeUpdate(sql); System.out.println(新增数据成功影响行数 rows); } catch (Exception e) { e.printStackTrace(); } finally { // 5. 释放资源增删改场景无需ResultSet JDBCUtils.close(conn, stmt); } } }3. 修改案例TestUpdate.java 中 update 部分package com.qcby; import java.sql.Connection; import java.sql.Statement; public class TestUpdate { public static void main(String[] args) { Connection conn null; Statement stmt null; try { conn JDBCUtils.getConnection(); stmt conn.createStatement(); // 修改SQL将用户名为“封装测试”的密码改为888888 String sql update t_user set password888888 where username封装测试; int rows stmt.executeUpdate(sql); System.out.println(修改数据成功影响行数 rows); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(conn, stmt); } } }4. 删除案例TestUpdate.java 中 delete 部分package com.qcby; import java.sql.Connection; import java.sql.Statement; public class TestUpdate { public static void main(String[] args) { Connection conn null; Statement stmt null; try { conn JDBCUtils.getConnection(); stmt conn.createStatement(); // 删除SQL删除用户名为“封装测试”的记录 String sql delete from t_user where username封装测试; int rows stmt.executeUpdate(sql); System.out.println(删除数据成功影响行数 rows); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(conn, stmt); } } }五、封装前后对比总结对比维度原生 JDBC 写法工具类封装写法代码量每个业务都要写连接、释放资源代码冗余仅关注业务 SQL代码量减少 60% 以上可维护性数据库信息硬编码修改需改动多处代码配置文件统一管理修改仅需改动配置文件错误率手动关闭资源易遗漏导致连接泄漏工具类统一处理避免资源泄漏问题复用性无复用性每个业务重复造轮子工具类可在所有业务中直接调用六、运行与验证步骤检查配置文件确认db.properties中的账号、密码、URL 配置正确运行查询案例执行TestJDBCUtils.java控制台输出t_user表所有数据运行新增案例执行TestUpdate.java中的新增代码控制台输出影响行数1数据库新增一条数据运行修改案例执行修改代码数据库中对应记录的密码被更新运行删除案例执行删除代码数据库中新增的测试数据被删除七、后续优化方向其他博客有介绍引入PreparedStatement防止 SQL 注入封装事务管理方法实现业务操作的原子性增加连接池如 Druid提升数据库连接性能

相关文章:

Java JDBC 封装:从原生写法到工具类封装 + 增删改查

在 Java 操作数据库的过程中,原生 JDBC 代码存在大量重复逻辑:加载驱动、获取连接、释放资源…… 这些代码在每个业务中都要写一遍,不仅繁琐,还容易出错。 本文是个人的一些学习笔记,主要内容如下: 原生 …...

5G NR上行控制信息复用:PUSCH信道上的UCI资源映射实战解析

1. 5G NR上行控制信息复用基础概念 在5G NR系统中,上行控制信息(UCI)的传输是保证通信质量的关键环节。UCI通常包含HARQ-ACK反馈、信道状态信息(CSI)和调度请求(SR)等重要内容。这些信息可以通过…...

【限时解禁】SITS2026白皮书技术附录首曝:7类AGI基准测试用例、37项性能指标定义及实测误差边界

第一章:SITS2026发布:AGI发展白皮书 2026奇点智能技术大会(https://ml-summit.org) 《SITS2026 AGI发展白皮书》由全球32家顶尖AI研究机构联合编制,首次系统定义通用人工智能(AGI)的可验证能力边界、安全对齐基准与跨…...

维普和知网AIGC检测有什么区别?不同平台降AI策略全解读

维普和知网AIGC检测有什么区别?不同平台降AI策略全解读 毕业季最让人头疼的问题之一:学校到底用哪个平台查AI率? 有的学校用知网,有的学校用维普,还有的学校两个都查。问题是同一篇论文,知网查出来15%&am…...

Pixel Aurora Engine 构建数字人素材库:快速生成多样化人物肖像与表情

Pixel Aurora Engine 构建数字人素材库:快速生成多样化人物肖像与表情 1. 数字人素材生产的行业痛点 在虚拟主播、游戏NPC和在线教育数字人项目中,高质量的人物素材需求正呈现爆发式增长。传统制作方式面临着三大核心挑战: 成本高昂&#…...

计算机视觉与深度学习 | 视觉SLAM研究综述

文章目录 一、视觉SLAM的核心原理与数学基础 1.1 前端视觉里程计 1.2 后端优化 1.3 回环检测 1.4 建图 二、主流算法与分类 2.1 基于特征点的SLAM(Feature-based / Indirect SLAM) 2.2 直接法SLAM(Direct SLAM) 2.3 视觉-惯性SLAM(VI-SLAM) 2.4 基于深度学习的SLAM 三、未…...

构建高效原神数据API:genshin.dev API完全指南

构建高效原神数据API:genshin.dev API完全指南 【免费下载链接】api A fan-made Genshin Impact API for easy access to game data. 项目地址: https://gitcode.com/gh_mirrors/api13/api 在游戏开发、数据分析、社区工具构建等场景中,获取准确、…...

Yocto WIC与WKS文件:从分区布局到镜像定制的深度解析

1. WIC镜像与WKS文件基础认知 第一次接触Yocto项目的开发者,往往会对WIC和WKS这两个术语感到困惑。简单来说,WIC(Wic Image Creator)是Yocto项目中的一种镜像生成工具,而WKS(Wic Kickstart)文件…...

JPEXS Free Flash Decompiler:终极SWF反编译工具,轻松提取Flash文件资源

JPEXS Free Flash Decompiler:终极SWF反编译工具,轻松提取Flash文件资源 【免费下载链接】jpexs-decompiler JPEXS Free Flash Decompiler 项目地址: https://gitcode.com/gh_mirrors/jp/jpexs-decompiler 还在为那些无法打开的旧版Flash文件而烦…...

从光场相机到手机摄影:聊聊那些让你‘先拍照后对焦’的黑科技是怎么实现的

从光场相机到手机摄影:揭秘“先拍照后对焦”背后的技术革命 你是否曾在拍完照片后,发现焦点没有对准想要的主体?或是拍完人像照片后,想要调整背景虚化程度?这些看似神奇的功能,其实都源自于一项被称为“光场…...

STM32CubeMX实战:ADC采集光敏电阻数据实现环境光照监测

1. 光敏电阻与ADC采集基础 光敏电阻是一种常见的光照传感器,它的核心特性是电阻值会随着光照强度的变化而改变。在实际应用中,我们通常需要将这种模拟量的变化转换为数字信号,这时候就需要用到模数转换器(ADC)。STM32系…...

今天不看就晚了:AGI创造性能力评估标准即将升级,3大新增硬性阈值倒计时披露

第一章:AGI创造性能力评估标准升级的紧迫性与战略意义 2026奇点智能技术大会(https://ml-summit.org) 当前主流AGI评估框架(如BIG-Bench、MMLU、GPQA)仍以知识覆盖度与推理一致性为核心指标,严重低估了跨模态隐喻生成、约束性原…...

SAP ECC6 EC-CS 标准报表项目(FS Item)× SAP 标准总账科目对照版

SAP ECC6 EC-CS 标准报表项目(FS Item) SAP 标准总账科目对照版(Excel 可直接下载,适配中国企业会计准则 IFRS,含事务码映射、必填字段、映射逻辑,可直接导入 CX16 做科目映射)⚠️ 核心说明编…...

如何快速掌握免费开源动画工具:MTB Nodes终极指南

如何快速掌握免费开源动画工具:MTB Nodes终极指南 【免费下载链接】comfy_mtb Animation oriented nodes pack for ComfyUI 项目地址: https://gitcode.com/gh_mirrors/co/comfy_mtb 想要在ComfyUI中轻松制作专业级动画效果?MTB Nodes作为专为动画…...

宏基AS6530笔记本时序解析:从G3到S0的硬件启动密码

1. 宏基AS6530笔记本的硬件启动密码:从G3到S0的时序解析 当你按下笔记本电源键的那一刻,主板就像在解一道精密的数学题——每个电压和信号必须按照特定顺序出现,错一步就会导致启动失败。宏基AS6530采用的广达ZK3代工板,其启动时序…...

FreeRTOS+Trace(03) 实战:TraceRecorder配置优化与内存占用分析

1. TraceRecorder基础配置实战 刚接触FreeRTOS Trace功能时,我踩过不少配置的坑。记得第一次用TraceRecorder时,直接用了默认配置,结果跑了不到5秒就把内存撑爆了。后来才发现,trcConfig.h这个文件里的参数需要根据实际项目情况仔…...

Translumo:打破语言壁垒的终极解决方案——实时屏幕翻译工具深度解析

Translumo:打破语言壁垒的终极解决方案——实时屏幕翻译工具深度解析 【免费下载链接】Translumo Advanced real-time screen translator for games, hardcoded subtitles in videos, static text and etc. 项目地址: https://gitcode.com/gh_mirrors/tr/Translum…...

金融RAG毫秒级响应实战

RAG服务在金融高并发场景下实现毫秒级检索与生成&#xff0c;是一场在性能、准确性与系统稳定性之间走钢丝的极限挑战。金融场景的查询&#xff08;如实时股价分析、合规审查、风险预警&#xff09;不仅要求极高的响应速度&#xff08;通常<200ms SLA&#xff09;&#xff0…...

Redis 和 MySQL 数据同步方案,ElasticSearch 和 MySQL 数据同步方案

Redis 和 MySQL 数据同步方案&#xff0c;ElasticSearch 和 MySQL 数据同步方案 一、Redis 数据同步方案二、ES 数据同步方案三、AI 的回答&#xff08;凑个字数&#xff0c;直接忽略&#xff09; 作为一名 Java 开发&#xff0c;处理 MySQL 与 Redis、Elasticsearch&#xff0…...

逆向网易云音乐加密接口:从搜索到播放的完整爬虫实践

1. 逆向网易云音乐加密接口的核心思路 第一次接触网易云音乐接口逆向时&#xff0c;我也被它复杂的加密机制搞得一头雾水。但经过多次实践后发现&#xff0c;整个过程其实可以拆解为两个关键环节&#xff1a;搜索关键词加密和歌曲ID加密。这两个环节就像接力赛的两棒&#xff0…...

Calibre中文路径保护插件:告别拼音路径,让中文电子书管理更优雅

Calibre中文路径保护插件&#xff1a;告别拼音路径&#xff0c;让中文电子书管理更优雅 【免费下载链接】calibre-do-not-translate-my-path Switch my calibre library from ascii path to plain Unicode path. 将我的书库从拼音目录切换至非纯英文&#xff08;中文&#xff0…...

016、高效微调框架介绍:Axolotl、LLaMA-Factory等工具对比

调试手记:为什么我的微调总在OOM?聊聊那些救命的微调框架 昨天深夜又被同事的电话叫醒,他的4090在微调7B模型时再次爆显存。“明明按照官方教程来的,怎么batch_size=2都跑不起来?”电话那头的声音透着疲惫。这场景太熟悉了,三周前我也在同样的坑里挣扎过。今天咱们不聊理…...

终极指南:如何快速掌握OpenBoardView开源电路板查看器的完整使用技巧

终极指南&#xff1a;如何快速掌握OpenBoardView开源电路板查看器的完整使用技巧 【免费下载链接】OpenBoardView View .brd files 项目地址: https://gitcode.com/gh_mirrors/op/OpenBoardView 你是否曾为复杂的电路板文件分析而烦恼&#xff1f;面对密密麻麻的元器件布…...

3步搭建你的专属麻将AI教练:Akagi实战指南

3步搭建你的专属麻将AI教练&#xff1a;Akagi实战指南 【免费下载链接】Akagi 支持雀魂、天鳳、麻雀一番街、天月麻將&#xff0c;能夠使用自定義的AI模型實時分析對局並給出建議&#xff0c;內建Mortal AI作為示例。 Supports Majsoul, Tenhou, Riichi City, Amatsuki, with t…...

ComfyUI动画制作终极实战指南:MTB Nodes全功能深度解析

ComfyUI动画制作终极实战指南&#xff1a;MTB Nodes全功能深度解析 【免费下载链接】comfy_mtb Animation oriented nodes pack for ComfyUI 项目地址: https://gitcode.com/gh_mirrors/co/comfy_mtb 在数字内容创作领域&#xff0c;动画制作、人脸处理和帧插值技术正成…...

从t检验到p值:Pearson相关系数显著性检验的统计逻辑探秘

1. 从t检验到相关系数&#xff1a;统计检验的桥梁 记得我第一次接触Pearson相关系数显著性检验时&#xff0c;看到那个神奇的t统计量公式t r / sqrt((1-r^2)/(n-2))&#xff0c;脑子里全是问号。为什么自由度是n-2&#xff1f;为什么分母是1-r&#xff1f;这跟t检验有什么关系…...

从零开始构建SaaS多租户架构:SpringBoot + MyBatis-Plus动态数据源实战

1. 为什么选择SpringBoot MyBatis-Plus构建SaaS系统 最近公司要求将现有系统升级为SaaS架构&#xff0c;作为Java技术栈的团队&#xff0c;我们评估了多种方案后选择了SpringBoot MyBatis-Plus组合。这个选择主要基于三个实际考量&#xff1a;首先&#xff0c;SpringBoot的自…...

基于MAVROS的Offboard模式实现无人机精准悬停控制

1. Offboard模式与MAVROS基础解析 第一次接触无人机Offboard控制时&#xff0c;我盯着PX4官方文档里那句"必须保持2Hz以上指令频率"发了半小时呆——直到炸机三次后才明白&#xff0c;原来飞控和MAVROS的通信就像玩抛接球&#xff0c;稍有延迟就会失控。这种血泪教训…...

高通Camera驱动(4)-- 从configure_streams到Usecase的创建与匹配

1. configure_streams到Usecase的转换机制 当Android框架调用configure_streams接口后&#xff0c;高通Camera HAL会经历从流配置到具体场景(Usecase)创建的复杂决策过程。这个过程就像餐厅的点餐系统&#xff1a;顾客&#xff08;框架&#xff09;提交订单&#xff08;stream …...

Android应用卡顿?从SurfaceFlinger的VSYNC信号与缓冲区管理说起

Android应用卡顿&#xff1f;从SurfaceFlinger的VSYNC信号与缓冲区管理说起 每次滑动列表时出现的画面撕裂&#xff0c;或是动画播放时的帧率骤降&#xff0c;这些卡顿问题背后往往隐藏着Android图形系统的复杂调度逻辑。作为开发者&#xff0c;我们常常在应用层绞尽脑汁优化绘…...