手写jdbc 工具类(封装思维,解决硬编码...)

目录

前言

手写jdbc 工具类 

封装思维

对于封装思维的理解

举一个关于封装思维的例子

解决硬编码

什么是硬编码?

硬编码的例子:

解决办法

解法1 

解法2 

解法3 

jdbc工具类总的代码如下

资源关闭的先后问题

解决办法: 

总结


前言

  • 本篇博客,主要是为了帮助大家了解,什么是封装思维 和如何解决硬编码,以及他们的具体应用

手写jdbc 工具类 

封装思维

对于封装思维的理解

我们知道"封装" 这一词,我们最早是从面向对象的三个特征:1 封装  2 继承 3 多态 。了解的。

关于封装的含义

  1. 隐藏数据:在Java中通过使用访问权限修饰符和 getxx方法 和setxx方法 ,阻止外界非法访问数据
  2.  简化代码,方便多次调用(本次手写工具类中有应用)
  3.  把对象的属性和行为,看成一个密不可分的整体,将两者结合起来(封装在对象中)

举一个关于封装思维的例子

最近使用jdbc 连接数据库,完成通过控制台输出方式的一个学生管理系统。主要功能就是对学生进行增删改查 操作。但我们知道,我们的每一步操作,都包含许多重复的代码(除了我们书写的sql语句和调用相关方法,为参数赋值,得到目标数据之外)

如下图所示:

加载数据库驱动(使用的数据库jar 包)

  Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test666?useSSL=false","root","123");

以及 关闭各个资源

关闭的顺序为:后面使用的,先关闭

  try {
                if(rs != null) rs.close();
                if(stmt!=null) stmt.close();
                if (conn!= null) conn.close();
            } catch (SQLException e) {
                    throw new RuntimeException(e);
            }

正是因为存在这么多相同的代码,通过理解并使用"封装思维“想着能否把相同的代码(属性,方法),按照它们的功能或目的,写在一起,集中调用。

这就是为什么我要使用jdbc 工具类的原因

解决硬编码

什么是硬编码?

我们通常把直接写在 源代码的固定的值或数据,而不是通过变量、配置文件、环境变量或函数调用等方式动态地获取这些值。

硬编码的例子:

  • 在代码中直接写入数据库连接字符串、密码等敏感信息。
  • 在代码中直接写入文件路径、端口号、IP 地址等配置信息。
  • 在代码中直接写入固定的文本、数字或其他数据。

如下图所示:

  Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test666?useSSL=false","root","123");

解决办法

  • 1 创建配置文件,将硬编码写在配置文件中(这里我使用的是properties 配置文件)

 db.properties 配置文件

  • 2  使用properties 配置文件在Java中对应的Properties类型的对象,调用load方法解析读取配置文件内容

关于Properties类 的含义

  • 是properties 配置文件在Java中的一个对应类: Java。util.Properties  是Map 接口实现类,key -value 都是String类型

 

以下有三种解法,它们的区别,在于配置文件的加载路径不同,导致解析配置文件的方式也会有所不同。

解法1 
  • 要求添加的配置配置文件再当前项目下

代码如下

public class TestProperties {
    public static void main(String[] args) throws IOException {
        Properties props = new Properties();
// 解析配置文件
 props.load(new FileInputStream("db.properties"));
        // 获取数据
        String driver = props.getProperty("driverClass");
        System.out.println(driver);

    }
}
  • 发现在上面的代码中, FileInputStream("文件名“)相对路径

运行后发现:

从图片我们可以看见,找不到指定文件。

原因是当我们写入的参数为相对路径(文件名:这里是指:db.properties),是在当前项目下寻找,如果没找到,就会出现这样的错误。

当前项目路径为:

 System.out.println("当前路径:"+System.getProperty("user.dir"));
 FileInputStream("文件名“)相对路径,是相对与 user.dir路径:当前路径:D:\GPT浏览器下载\IDEA代码\日常代码集\project1

因此解决方法是:把配置文件移到project1 项目下

运行结果

解法2 
  • 要求读取的配置文件要和 引用class的这个 java文件在同一个包下,否则会报空指针异常。

代码如下

    Properties props = new Properties();
        // 要求读取的配置文件要和 引用class的这个 java文件在同一个包下,否则会报空指针异常
        InputStream in = TestProperties.class.getResourceAsStream("db.properties");
      System.out.println("当前路径:"+in);
       props.load(in);

        // 获取数据
        String driver = props.getProperty("driverClass");
        System.out.println(driver);

使用映射的方式 ,调用   TestProperties.class.getResourceAsStream("db.properties");

这里有个要求:

要求读取的配置文件要和 引用class的这个 java文件在同一个包下,否则会报空指针异常。

我们知道src文件夹下的文件都会经过编译后在classes文件夹下产生对应的字节码文件

如下图所示:

运行结果

解法3 
  • 使用类加载器:ClassLoader,把硬盘的文件加载到内存上,要求配置文件应该放在类路径下(classPath)

如图所示:类加载器:ClassLoader具体应用场景

代码如下

 Properties props = new Properties();
        // 获取类加载器:getClassLoader()
        // 根据ClassLoader类加载器 获取资源(配置文件),要求资源放在类路径下 src目录下
        InputStream in = TestProperties.class.getClassLoader().getResourceAsStream("db.properties");
        System.out.println("当前路径:"+in);
        props.load(in);
        // 获取数据
        String driver = props.getProperty("driverClass");
        System.out.println(driver);

运行结果

在之后运行手写的jdbc工具类代码,将加载驱动(数据库jar包)路径作了修改。之前的不加cj方式,过时了。

修改之后,如图所示:

之前控制台会报错:

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

解决办法:
报错信息提示你在加载 MySQL 驱动类时使用了旧的驱动类 com.mysql.jdbc.Driver,而新的驱动类是 com.mysql.cj.jdbc.Driver。

注意:

在MySQL 版本在8.0之上(包括8.0版本)驱动已经通过服务提供者接口(SPI)自动注册,因此手动加载驱动类通常是不必要的
 

jdbc工具类总的代码如下

  • 在单线程下没有问题, 在多线程下有问题
  • ctrl + alt + t 把代码使用指定模版包裹(try-catch....)
  • 注意作用域问题(static 静态代码块中,在外部,无法被访问)
  • 使用类加载器;ClassLoader 解析读取配置文件内容
  • 可变参数( Object ... params ,可以任意控制输入数据的数量)
package it.Util;

import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
 * @Author: Administrator
 * @Description:
 * @Date: 2024/11/8 下午2:56
 * @Version: 1.0
 */
public class jdbcUtil {
// 数据库连接


    /**
     * jdbc的工具类
     *  在单线程下没有问题, 在多线程下有问题
     */

        static Properties props = new Properties();
        private static Connection conn;
        private  static PreparedStatement stmt;

        //使用静态代码块  加载数据库四大参数
        static {
            try {
                props.load(jdbcUtil.class.getClassLoader().getResourceAsStream("db.properties"));
                Class.forName(props.getProperty("driverClass"));
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * 获取连接对象
         *
         * @return Connection对象
         */
        public static Connection getConnection() throws SQLException {
            String jdbcUrl = props.getProperty("jdbcUrl");
            String username = props.getProperty("username");
            String password = props.getProperty("password");
            return DriverManager.getConnection(jdbcUrl, username, password);
        }


        public static void close( ResultSet rs) {
            try {
                if (rs != null) rs.close();
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * 执行增删改的sql的方法
         */
        public static int executeUpdate(String sql, Object... params) {
            //ctrl + alt + t 把代码使用指定模版包裹
            try {
                conn = getConnection();
                stmt = conn.prepareStatement(sql);
                //给问号赋值
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
                //执行
                return stmt.executeUpdate();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            } finally {
                close( null);
            }
        }

        public static ResultSet executeQuery(String sql, Object... params) throws SQLException {
            Connection conn = null;
            PreparedStatement pstmt = null;
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            //给问号赋值
            for (int i = 0; i < params.length; i++) {
                pstmt.setObject(i + 1, params[i]);
            }
            ResultSet resultSet = pstmt.executeQuery();
            //执行
            return resultSet;
        }
    }


在书写代码过程中,同样也遇到一些困难:

资源关闭的先后问题

原因:报错 No operations allowed after statement closed 表示尝试在一个已经关闭的数据库语句对象上执行操作。这通常发生在数据库连接或语句对象被关闭后,仍然尝试执行查询或更新操作

解决办法: 

在写查询方法时,不允许先关闭Connection 资源,prepareStatement 资源

再返回查询结果集。而是在测试类中,当我们的操作完成之后,再关闭所有资源

测试类代码:

 String sql="select *from user where userId=?";
    ResultSet resultSet=null;
    try {
      resultSet= jdbcUtil.executeQuery(sql, 1);
        if (resultSet.next()){
            String username = resultSet.getString("username");
            String pwd = resultSet.getString("pwd");
            System.out.println(username+"\t\t"+pwd);
            //System.out.println(resultSet);
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    finally {

        jdbcUtil.close(resultSet);
    }

}

运行结果:

总结

本篇博客,简单的复习了如何手写jdbc 工具类:如何理解 封装思维,解决硬编码问题 等问题

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据库的四个基本概念

数据&#xff0c;数据库&#xff0c;数据库管理系统和数据库系统是与数据库技术密切相关的4个基本概念。 1. 数据&#xff08;data&#xff09; 描述事物的符号记录&#xff0c;譬如&#xff1a;数字、文字、图形、图像、音频、视频等&#xff0c;多种表现形式&#xff0c;均可…

java---认识异常(详解)

还有大家来到权权的博客~欢迎大家对我的博客提出意见哦&#xff0c;有错误会及时改进的~点击进入我的博客主页 目录 一、异常的概念及体系结构1.1 异常的概念1.2 异常的体系结构1.3异常的分类 二、异常的处理2.1防御式编程2.2 异常的抛出2.3 异常的捕获2.3.1异常声明throws2.3.…

移远通信亮相骁龙AI PC生态科技日,以领先的5G及Wi-Fi产品革新PC用户体验

PC作为人们学习、办公、娱乐的重要工具&#xff0c;已经深度融入我们的工作和生活。随着物联网技术的快速发展&#xff0c;以及人们对PC性能要求的逐步提高&#xff0c;AI PC成为了行业发展的重要趋势。 11月7-8日&#xff0c;骁龙AI PC生态科技日在深圳举办。作为高通骁龙的重…

【云原生开发】namespace管理的后端开发设计与实现

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

老破机器硬盘要坏,转移虚拟机里的打字平台过程全记录

我有一台老破机器&#xff0c;说破其实没多破&#xff0c;但是老应该是有几年了&#xff0c;这机器一开始一直放在领导办公室不让人用&#xff0c;后来因为单位整体搬迁&#xff0c;我跟领导讨了来&#xff0c;win10的系统&#xff0c;我装了个虚拟机好像是15的版本&#xff0c…

【JavaEE初阶】多线程上部

文章目录 本篇目标&#xff1a;一、认识线程&#xff08;Thread&#xff09;1.概念&#xff1a;2.创建线程 二、Thread 类及常见方法2.1 Thread 的常见构造方法2.2 Thread 的几个常见属性2.3 启动⼀个线程 - start()2.4 中断⼀个线程2.5 等待⼀个线程 - join()2.6 获取当前线程…

[vulnhub] Corrosion: 2

https://www.vulnhub.com/entry/corrosion-2,745/ 提示&#xff1a;枚举才是神 主机发现端口扫描 使用nmap扫描网段类存活主机 因为靶机是我最后添加的&#xff0c;所以靶机IP是6 &#xff0c;kali是10 nmap -sP 192.168.56.0/24 Starting Nmap 7.94SVN ( https://nmap.org ) …

MySQL数据库的备份与还原

目录 mysql 数据库的备份 生成SQL脚本 1 在控制台使用mysqldump命令可以用来生成指定数据库的脚本 ​编辑2 在数据库图形化界面工具&#xff1a;DateGrip 中操作&#xff1a;导出 mysql 数据库的还原 执行SQL脚本 1 在控制台使用 命令&#xff0c;指定将sql脚本导入到指定…

ASR 点亮闪光灯和后摄对焦马达

ASR翱捷科技 ASR kernel 5.10 android14 ASR EVB平台 ASR 原理图 闪光灯是gpio控制 1.驱动 路径:asr\kernel\linux\drivers\media\platform\asr-mars11\flash\leds-gpio-flash.c 驱动加载后生成设备节点/sys/class/leds/torch 和/sys/class/leds/flash。 Makefile Kconfig…

【大数据学习 | HBASE】hbase的读数据流程与hbase读取数据

1. hbase的读数据流程 在解析读取流程之前我们还需要知道两个功能性的组件和HFIle的格式信息 HFILE 存储在hdfs中的hbase文件&#xff0c;这个文件中会存在hbase中的数据以kv类型显示&#xff0c;同时还会存在hbase的元数据信息&#xff0c;包括整个hfile文件的索引大小&…

【GPTs】MJ Prompt Creator:轻松生成创意Midjourney提示词

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | GPTs应用实例 文章目录 &#x1f4af;GPTs指令&#x1f4af;前言&#x1f680; MJ Prompt Creator主要功能适用场景优点缺点 &#x1f4af; 小结 &#x1f4af;GPTs指令 中文翻译&#xff1a; 任务说明 您是一款为幻灯片…

实现3D热力图

实现思路 首先是需要用canvas绘制一个2D的热力图&#xff0c;如果你还不会&#xff0c;请看json绘制热力图。使用Threejs中的canvas贴图&#xff0c;将贴图贴在PlaneGeometry平面上。使用着色器材质&#xff0c;更具json中的数据让平面模型 拔地而起。使用Threejs内置的TWEEN&…

ATom: 矿物粉尘在卷云形成中的主导作用

目录 ATom: Dominant Role of Mineral Dust in Cirrus Cloud Formation 简介 摘要 代码 引用 网址推荐 知识星球 机器学习 ATom: Dominant Role of Mineral Dust in Cirrus Cloud Formation 简介 该数据集提供了&#xff1a;&#xff08;1&#xff09;由 NOAA 粒子分析…

C语言 | Leetcode C语言题解之第560题和为K的子数组

题目&#xff1a; 题解&#xff1a; // 暴力美学&#xff1a;20行C代码 int subarraySum(int *nums, int numsSize, int k) {int count 0;// 弄个大数组做个暴力的Hash表&#xff0c;大概4*20M*2160M。用calloc初始化为全零。int *maps (int *)calloc(1001 * 20001 * 2, siz…

基于vue框架的的社区居民服务管理系统8w86o(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;居民,楼房信息,报修信息,缴费信息,维修进度 开题报告内容 基于Vue框架的社区居民服务管理系统开题报告 一、研究背景与意义 随着城市化进程的加速&#xff0c;社区居民数量激增&#xff0c;社区管理面临着前所未有的挑战。传统的社区…

UE5.4 PCG 自定义PCG蓝图节点

ExecuteWithContext&#xff1a; PointLoopBody&#xff1a; 效果&#xff1a;点密度值与缩放成正比

[ Linux 命令基础 2 ] Linux 命令详解-系统管理命令

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

单链表算法题(数据结构)

1. 反转链表 https://leetcode.cn/problems/reverse-linked-list/description/ 题目&#xff1a; 看到这个题目的时候我们怎么去想呢&#xff1f;如果我们反应快的话&#xff0c;应该可以想到我们可以从1遍历到5然后依次头插&#xff0c;但是其实我们还有更好的办法&#xff…

Java代码审计-模板注入漏洞

一、模板引擎 在Java开发当中&#xff0c;为了将前端和后端进行分离&#xff0c;降低项目代码的耦合性&#xff0c;使代码更加易于维护和管理。除去以上的原因&#xff0c;模板引擎还能实现动态和静态数据的分离。 二、主流模板引擎 在Java中&#xff0c;主流的模板引擎有:Fre…

SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based

关注这个靶场的其它相关笔记&#xff1a;SQLI LABS —— 靶场笔记合集-CSDN博客 0x01&#xff1a;过关流程 输入下面的链接进入靶场&#xff08;如果你的地址和我不一样&#xff0c;按照你本地的环境来&#xff09;&#xff1a; http://localhost/sqli-labs/Less-39/ 本关是堆…