首页技术文章正文

Java培训:自定义DBUtils

更新时间:2022-07-06 来源:黑马程序员 浏览量:

  1.1 概述

  如果只使用JDBC进行开发,冗余代码过多,为了简化JDBC开发。我们采用apache commons组件一个成员:DBUtils。

  DBUtils就是JDBC的简化开发工具包。需要项目导入commons-dbutils-1.6.jar才能够正常使用DBUtils工具。

  DBUtils是java编程中的数据库操作实用工具,小巧简单实用。DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。

  本案例就是模拟DBUtils的功能自定义一个简化JDBC开发的工具HMDButils,目的练习反射的内容。

  HMDButils三个核心功能介绍

  HMQueryRunner中提供对sql语句操作的API.

  HMResultSetHandler接口,用于定义select操作后,怎样封装结果集.

  HMDbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

  ## 1.2 HMQueryRunner核心类

  HMQueryRunner核心类源代码:

  ```java

package com.itheima.dbutils;

import com.itheima.dbutils.inter.HMResultSetHandler;
import com.itheima.dbutils.utils.HMQueryRunnerUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class HMQueryRunner {
    private DataSource ds;
    //空参构造
    public HMQueryRunner() {
    }

    //有参构造
    public HMQueryRunner(DataSource ds) {
        this.ds = ds;
    }

    //执行增删改
    public int update(String sql,Object ... params) throws SQLException {
        return update(ds.getConnection(),sql,params);
    }

    //执行增删改
    public int update(Connection con, String sql,Object ... params) throws SQLException {
        //1.调用方法获取PreparedStatement对象(已经给?完成了赋值)
        PreparedStatement pstmt = HMQueryRunnerUtils.preparedStatement(con, sql, params);
        //5.执行查询
        int result = pstmt.executeUpdate();
        //6.返回结果
        return result;
    }

    //执行查询
    public <T> T query(String sql, HMResultSetHandler<T> hmrsh, Object ... params) throws SQLException {
        return query(ds.getConnection(),sql,hmrsh,params);
    }

    //执行查询
    public <T> T query(Connection con, String sql, HMResultSetHandler<T> hmrsh, Object ... params) throws SQLException {
        //1.调用方法,执行查询
        ResultSet rs = HMQueryRunnerUtils.getResultSet(con, sql, params);
        //2.调用结果集处理器的handler方法,处理结果集
        T t = hmrsh.handler(rs);
        //返回结果对象t
        return t;
    }
}

  HMQueryRunner核心类中使用的工具类HMQueryRunnerUtils的源代码:

  ```java

package com.itheima.dbutils.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;

public class HMQueryRunnerUtils {
    //构造方法private修饰
    private HMQueryRunnerUtils(){}
    //静态方法,获取PreparedStatement对象
    public static PreparedStatement preparedStatement(Connection con, String sql, Object ... params) throws SQLException {
        //1.获取执行sql语句的PreparedStatement对象
        PreparedStatement pstmt = con.prepareStatement(sql);
        //2.获取sql语句参数的ParameterMetaData对象
        ParameterMetaData pmd = pstmt.getParameterMetaData();
        //3.获取sql语句中?的数量
        int count = pmd.getParameterCount();
        //System.out.println(count);
        //4.给?号赋值
        for(int i = 0;i<count;i++) {
            pstmt.setObject((i+1),params[i]);
        }
        //5.返回PreparedStatement对象
        return pstmt;
    }
    //执行查询获取结果集
    public static ResultSet getResultSet(Connection con, String sql, Object ... params) throws SQLException {
        //1.调用方法获取PreparedStatement对象(已经给?完成了赋值)
        PreparedStatement pstmt = preparedStatement(con, sql, params);
        //2.执行查询
        ResultSet rs = pstmt.executeQuery();
        //3.返回结果集
        return rs;
    }
    public static <T> T getInstance(ResultSet rs,Class<T> clazz, ResultSetMetaData rmd, int count) throws InstantiationException, IllegalAccessException, SQLException, NoSuchMethodException, ClassNotFoundException, InvocationTargetException {
        //6.反射创建对象
        T t = clazz.newInstance();
        //7.获取所以字段名,调用set方法完成对象的赋值
        for (int i = 0; i < count; i++) {
            String columnName = rmd.getColumnName(i + 1);
            //8.调用方法,根据字段名获取对应的set方法名称
            String setMethodName = getSetMethodName(columnName);
            //9.获取列类型对应的java类型的全类名
            String columnClassName = rmd.getColumnClassName(i + 1);

            //9.反射获取set方法对象
            Method setMethod = clazz.getMethod(setMethodName, Class.forName(columnClassName));
            //10.执行set方法对象,给属性赋值
            setMethod.invoke(t,rs.getObject(i+1));
        }
        return t;
    }

    //根据字段名称,获取对应的Set方法名称
    private static String getSetMethodName(String fieldName) {
        return "set".concat(fieldName.substring(0,1).toUpperCase().concat(fieldName.substring(1)));
    }
}

  1.2.1 构造方法使用-提供数据源

  构造方法

  `HMQueryRunner(DataSource) ` 创建核心类,并提供数据源,内部自己维护Connection

  普通方法

  `update(String sql , Object ... params) ` 执行DML语句

  `query(String sql , HMResultSetHandler , Object ... params) ` 执行DQL语句,并将查询结果封装到对象中。

  1.2.2 构造方法使用-不提供数据源

  构造方法

  `HMQueryRunner()` 创建核心类,**没有**提供数据源,在进行具体操作时,需要手动提供Connection

  普通方法

  `update(Connection conn , String sql , Object ... params)` 使用提供的Connection,完成DML语句

  `query(Connection conn , String sql , HMResultSetHandler , Object ... params) ` 使用提供的Connection,执行DQL语句,并将查询结果封装到对象中。

  1.3 结果集处理器接口HMResultSetHandler源代码

  ```java

package com.itheima.dbutils.inter;

import java.sql.ResultSet;
import java.sql.SQLException;

/*
    结果集处理器接口
 */
public interface HMResultSetHandler<T> {
    //抽象方法
    public abstract T handler(ResultSet rs) throws SQLException;
}

  1.4 结果集处理器接口实现类

  HMBeanHandler:将结果集中第一条记录封装到一个指定的javaBean中。

package com.itheima.dbutils.impl;

import com.itheima.dbutils.inter.HMResultSetHandler;
import com.itheima.dbutils.utils.HMQueryRunnerUtils;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class HMBeanHandler<T> implements HMResultSetHandler<T> {

    private Class<T> clazz;
    public HMBeanHandler(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public T handler(ResultSet rs) throws SQLException {
        T t = null;
        try {
            //3.获取结果集元数据
            ResultSetMetaData rmd = rs.getMetaData();
            //4.获取列数量
            int count = rmd.getColumnCount();
            //5.处理结果集
            if(rs.next()) {
                t = HMQueryRunnerUtils.getInstance(rs,clazz, rmd, count);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return t;
    }
}

  HMBeanListHandler:将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中

  ```java

package com.itheima.dbutils.impl;

import com.itheima.dbutils.inter.HMResultSetHandler;
import com.itheima.dbutils.utils.HMQueryRunnerUtils;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class HMBeanListHandler<T> implements HMResultSetHandler<List<T>> {
    private Class<T> clazz;
    //构造方法
    public HMBeanListHandler(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public List<T> handler(ResultSet rs) throws SQLException {
        //2.创建List集合对象
        List<T> list = new ArrayList<>();
        try {
            //3.获取结果集元数据
            ResultSetMetaData rmd = rs.getMetaData();
            //4.获取列数量
            int count = rmd.getColumnCount();
            //5.处理结果集
            while(rs.next()) {
                T t = HMQueryRunnerUtils.getInstance(rs,clazz, rmd, count);
                //11.把对象添加到List集合对象中
                list.add(t);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return list;
    }
}

  HMScalarHandler:它是用于单数据。例如select count(*) from 表操作。

  ```java

package com.itheima.dbutils.impl;

import com.itheima.dbutils.inter.HMResultSetHandler;

import java.sql.ResultSet;
import java.sql.SQLException;

public class HMScalarHandler<T> implements HMResultSetHandler<T> {
    private final int columnIndex;
    private final String columnName;

    public HMScalarHandler() {
        this(1, null);
    }

    public HMScalarHandler(int columnIndex) {
        this(columnIndex,null);
    }

    public HMScalarHandler(String columnName) {
        this(1,columnName);
    }

    private HMScalarHandler(int columnIndex, String columnName) {
        this.columnIndex = columnIndex;
        this.columnName = columnName;
    }

    @Override
    public T handler(ResultSet rs) throws SQLException {
        T t = null;
        //5.处理结果集
        if(rs.next()) {
            if(columnName == null) {
                t = (T)rs.getObject(columnIndex);
            } else {
                t = (T)rs.getObject(columnName);
            }

        }
        return t;

    }
}

  HMColumnListHandler:将结果集中指定的列的字段值,封装到一个List集合中

  ```java

package com.itheima.dbutils.impl;

import com.itheima.dbutils.inter.HMResultSetHandler;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class HMColumnListHandler<T> implements HMResultSetHandler<List<T>> {
    private final int columnIndex;
    private final String columnName;

    public HMColumnListHandler() {
        this(1,null);
    }

    public HMColumnListHandler(int columnIndex) {
        this(columnIndex,null);
    }

    public HMColumnListHandler(String columnName) {
        this(1,columnName);
    }

    private HMColumnListHandler(int columnIndex, String columnName) {
        this.columnIndex = columnIndex;
        this.columnName = columnName;
    }

    @Override
    public List<T> handler(ResultSet rs) throws SQLException {
        //2.创建List集合对象
        List<T> list = new ArrayList<>();

        //3.获取结果集元数据
        ResultSetMetaData rmd = rs.getMetaData();
        //4.获取列数量
        int count = rmd.getColumnCount();
        //5.处理结果集
        while(rs.next()) {
            Object obj = null;
            if(columnName == null) {
                obj = rs.getObject(columnIndex);
            } else {
                obj = rs.getObject(columnName);
            }
            list.add((T)obj);
        }

        return list;
    }
}

  然后把我们的整个模块打成jar包,就可以通过导入jar包的方式进行使用了(本文档提供打好的jar包)

  关于如何把idea中模块打成jar包,这里就不再详细描述,可以百度搜索: idea中如何将代码打成jar包

1657076346085_idea中如何将代码打成jar包.jpg

  总结

  1.此篇文章用来模拟DBUtils简化JDBC操作数据库的复杂步骤

  2.大量使用反射,让代码更为灵活,使用者更加方便

  3.方法参数是接口,调用者可以根据需求传递具体的实现了,如果感觉实现类不合适,可以自己定义实现类,提高了代码的扩展性

分享到:
在线咨询 我要报名
和我们在线交谈!