目录
前言
手写jdbc 工具类
封装思维
对于封装思维的理解
举一个关于封装思维的例子
解决硬编码
什么是硬编码?
硬编码的例子:
解决办法
解法1
解法2
解法3
jdbc工具类总的代码如下
资源关闭的先后问题
解决办法:
总结
前言
- 本篇博客,主要是为了帮助大家了解,什么是封装思维 和如何解决硬编码,以及他们的具体应用
手写jdbc 工具类
封装思维
对于封装思维的理解
我们知道"封装" 这一词,我们最早是从面向对象的三个特征:1 封装 2 继承 3 多态 。了解的。
关于封装的含义
- 隐藏数据:在Java中通过使用访问权限修饰符和 getxx方法 和setxx方法 ,阻止外界非法访问数据
- 简化代码,方便多次调用(本次手写工具类中有应用)
- 把对象的属性和行为,看成一个密不可分的整体,将两者结合起来(封装在对象中)
举一个关于封装思维的例子
最近使用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 工具类:如何理解 封装思维,解决硬编码问题 等问题