JDBCutil自己写的源码——帮助理解原理

因为这个JDBCutil是博主自己学了反射的知识以后然后这边进行一个记录一下自己的学习历程。

然后这边每一条的代码我都有详细的标注。能够确保小白都能看懂。

这边需要引入一个工厂的依赖。

这边把这个源码简单的讲解一下:

        其实简单来说就是,通过这个依赖利用配置文件去创建一个工厂,然后后面的方法里面都需要去拿到这样一个的链接对象,当然这个工厂里面肯定会有很多的对象,所以我们用了一个就需要还给他,有借有还嘛,对吧。所以我们在方法执行完以后都需要去关闭这个资源,这样就相对的归还了这个对象。

        在每一个的方法里面我们都需要去拿到有一个数据库的链接对象。然后根据需要去得到这样一个预编译对象或者是拼接语句的对象,以及相对应的这个包装类的class对象,因为查询语句这边处理是获取一个class对象然后去实例化,然后分装,然后再返回给调用位置。每一个位置都有用到反射。所以说反射其实是很重要的。如果可以在渗透过程中用到反射的话,那么权限的设置形同虚设。一切java对象的爸爸。

        所以源码与原理理解以后你会收获很多,其他的不多说,代码如下:

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 反射的使用:
 * 其实反射是依赖于一个class对象,叫做字节码对象
 * 百度百科:对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;
 *
 * 我们只能通过setAccessible方法设置方法的访问权限。然后再获取。这就体现了反射的一点缺陷。理论上反射可以访问任
 * 何类中的的任何方法或者属性,权限修饰符在它面前简直就是弟弟,想改就改了。反射就是爸爸,这样就导致了不安全的状态。
 */

/**
 * @ClassName:JDBCutil
 * @Author 忆林
 * @Date 23:42 2022/5/26
 * @Description //TODO
 * @version v1.0
 * @describle:jdbc的代码实现!!!
 **/

public class JDBCutil {
   public static void main(String[] args) {

   }
   static DataSource dataSource;
   static{
       try {
           //通过类加载来获取jabc的配置文件信息
           InputStream inputStream = cn.smxy.ProjectS01_217.dao.JDBCutil.class.getResourceAsStream("/jdbc.properties");
           //使用Properties对象操作properties文件
           Properties properties = new Properties();
           //将配置文件加载到Properties对象中.加载配置文件中的所有属性
           properties.load(inputStream);
           //通过druid来创建一个工厂类
           dataSource = DruidDataSourceFactory.createDataSource(properties);
       } catch (Exception e) {
           e.printStackTrace();
       }

   }
   //获取数据库操作对象,调用后记得还给我
   public static Connection getConnection ()  {
       try {
           return dataSource.getConnection();
       } catch (SQLException throwables) {
           System.out.println("返回数据库链接失败,数据库工具管理系统有问题!!!");
           throwables.printStackTrace();
           return null;
       }
   }
   //还数据库操作对象,如果后期有问题应该是在这里

   /**\
    *为什么要关闭Statement对象!!!!
    * @param connection
    * @param statement
    */
   public static void close(Connection connection, Statement statement) {
       try {
           connection.close();
       } catch (SQLException throwables) {
           throwables.printStackTrace();
       }
       try {
           statement.close();
       } catch (SQLException throwables) {
           throwables.printStackTrace();
       }
   }
   //通用的增删改
   public static int update(String sql,Object...args){
       Connection connection = null;
       PreparedStatement preparedStatement = null;
       try {
//            获取链接
           connection = dataSource.getConnection();
//            获取预编译对象
           preparedStatement = connection.prepareStatement(sql);
//            通过预编译对象返回相应的SQL语句然后得到占位符————简单来说就是获取源数据,得到占位符
           ParameterMetaData metaData = preparedStatement.getParameterMetaData();
//            得到占位符个数
           int count = metaData.getParameterCount();
           for(int i=1;i<=count;i++){
//                根据变量属性动态赋值,且SQL语句下标为1开始
               preparedStatement.setObject(i,args[i-1]);
           }
//            返回相对应的操作数据个数
           return preparedStatement.executeUpdate();
       } catch (SQLException throwables) {
           throwables.printStackTrace();
           return 0;
       }finally {
           //关闭资源还给数据库
           close(connection,preparedStatement);
       }
   }
   //通用查询方法
   //第一个是用来声明类型参数的,后面的两个才是泛型的实现。
   //
   //也就是告诉大家 <T>这是一种类型

   /**
    * 然后这边的这个List返回值我想明确的说明一下就是说,为了解耦合
    * 实现sql与其他的代码的分离所以才会用一个list返回
    * @param sql
    * @param args
    * @param <T>
    * @return
    * 但是使用泛型,您定义 Class.newInstance() 方法具有一个更加特定的返回类型:
    * 使用泛型的返回一个指定类型的类,用来封装这个类
    */
   public static<T>  List<T> Equery(String sql,Class<T> tClass,Object...args){
       Connection connection = null;
       PreparedStatement preparedStatement = null;
       ResultSet resultSet = null;
       List<T> list = new ArrayList<>();
       try{
           /**
            * 这边重复了上面的操作就不细细的注释了
            */
           //获取链接
           connection = dataSource.getConnection();
           //获取数据库的预编译对象queryrunner
           preparedStatement = connection.prepareStatement(sql);
           //通过预编译对象获取源数据对于这个预编译对象的元数据
           ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
           //通过源数据获取占位符
           int count = parameterMetaData.getParameterCount();
           for(int i=0;i<count;i++){
               preparedStatement.setObject(i+1,args[i]);
           }
           //执行sql语句
           /**
            * Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回
            * true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。
            * Statement的executeQuery(String query)接口用来执行select查询,并且返回ResultSet。即使查询不到记录返回的
            * ResultSet也不会为null。我们通常使用executeQuery来执行查询语句,这样的话如果传进来的是insert或者update语句的
            */

           /**
            * 其实在查询的时候即使数据库的后台属性与java的类属性不一致
            * 的时候可以采用将这个数据库的查询语句取一个别名,这个时候别名与类的属性名要对应
            * 此时我们的查询的结果返回值的头就是以别名来命名的所以可以进行一个封装。
            */
           resultSet = preparedStatement.executeQuery();
           //遍历集合,利用反射的方法
           while(resultSet.next()){
               //获取一个指定的封装对象
               //调用空参构造得到一个新的对象
               //Class类的getDeclaredConstructor()方法,可获取到类的私有构造器(包括带有其他修饰符的构造器),
               // 但在使用private的构造器时,必须设置setAccessible()为true,才可以获取并操作该Constructor对象
               /**
                * Class类的getDeclaredConstructor()方法,可获取到类的私有构造器(包括带有其他修饰符的构造器),但
                * 在使用private的构造器时,必须设置setAccessible()为true,才可以获取并操作该Constructor对象
                * 因为我们会传一个对象类型过来然后此时我们就不需要去得到这个构造器去构造对象,因为可以直接通过反射区构造对象,然后我们只需要将这个得到的反射的对象
                * 将它的权限设为最大,也就是拿到它的所有属性以及方法。
                *
                * 因为这边的是泛型,然后我要获取这个属性的话,就要将这个类名进行一个放射它的属性
                * 本身就是泛型无法获取它的本身属性因为他本身就是一个不确定的值
                */
               T t = tClass.newInstance();
               //获取该对象的所有声明的字段,注意是所有!!!!父类属性的所有属性
               Field[] fields = tClass.getDeclaredFields();
               //usename pss
               for(Field filed:fields){
                   String name = filed.getName();//属性名
                   //去filed取值
                   //use psss
                   Object value = resultSet.getObject(name);
                   //设置权限的最大值,暴力放射
                   //for循环的对象赋值拿到所有方法与属性
                   filed.setAccessible(true);
                   //属性赋值
                   filed.set(t,value);
               }
               /**
                *
                *
                *
                *
                *
                *
                *
                *
                *
                *
                *
                * 这边会有一个bug就是你的数据库里面不能存0的变量不然数据信息访问不到???
                */
               list.add(t);
           }
       }catch (Exception e){
           e.printStackTrace();
       }finally {
           close(connection,preparedStatement);
           try {
               resultSet.close();
           } catch (SQLException throwables) {
               throwables.printStackTrace();
           }
       }
       return list;
   }

   public static<T> List<T> StaQuery(Class<T> c,String str1,String str2){
       /**
        * select * from student where sta = sta2;
        */
       List<T> list = new ArrayList<>();
       Connection connection = null;
       Statement Statement = null;
       ResultSet resultSet = null;
       String sql = "select * from student where";
       try{
           connection = dataSource.getConnection();
           Statement = connection.createStatement();
           sql = sql+" "+str1+"='"+str2+"'";

           resultSet = Statement.executeQuery(sql);
           while (resultSet.next()){
               T t = c.newInstance();
               Field[] fields = c.getDeclaredFields();
               for(Field field:fields){
                   String temp = field.getName();
                   Object value = resultSet.getObject(temp);
                   field.setAccessible(true);
                   /**
                    * 这边暴力反射以后,将他进行一个赋值的话,如果这个数据从后端取过来的话是null的话赋值问题可能会赋值出问题
                    * 比如说null赋值给int 然后这边就会抛异常,然后这边就会有点问题
                    * 也就是这个数据会取不到
                    */
                   field.set(t,value);
               }
               list.add(t);
           }
       }catch (Exception e){
           e.printStackTrace();
       }finally {
           close(connection,Statement);
           try {
               resultSet.close();
           } catch (SQLException throwables) {
               throwables.printStackTrace();
           }
       }
       return list;
   }
}

愿所有整装待发的开始,都能在匆匆岁月中为时不晚!!!

大伙加油叭,学习是一个漫长的过程!慢慢靠近,233333333333! 

posted @ 2022-06-01 16:34  忆林pp  阅读(20)  评论(0)    收藏  举报  来源