首頁技術(shù)文章正文

Java培訓(xùn):自定義DBUtils

更新時間:2022-07-06 來源:黑馬程序員 瀏覽量:

  1.1 概述

  如果只使用JDBC進(jìn)行開發(fā),冗余代碼過多,為了簡化JDBC開發(fā)。我們采用apache commons組件一個成員:DBUtils。

  DBUtils就是JDBC的簡化開發(fā)工具包。需要項目導(dǎo)入commons-dbutils-1.6.jar才能夠正常使用DBUtils工具。

  DBUtils是java編程中的數(shù)據(jù)庫操作實用工具,小巧簡單實用。DBUtils封裝了對JDBC的操作,簡化了JDBC操作,可以少寫代碼。

  本案例就是模擬DBUtils的功能自定義一個簡化JDBC開發(fā)的工具HMDButils,目的練習(xí)反射的內(nèi)容。

  HMDButils三個核心功能介紹

  HMQueryRunner中提供對sql語句操作的API.

  HMResultSetHandler接口,用于定義select操作后,怎樣封裝結(jié)果集.

  HMDbUtils類,它就是一個工具類,定義了關(guān)閉資源與事務(wù)處理的方法

  ## 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;
    //空參構(gòu)造
    public HMQueryRunner() {
    }

    //有參構(gòu)造
    public HMQueryRunner(DataSource ds) {
        this.ds = ds;
    }

    //執(zhí)行增刪改
    public int update(String sql,Object ... params) throws SQLException {
        return update(ds.getConnection(),sql,params);
    }

    //執(zhí)行增刪改
    public int update(Connection con, String sql,Object ... params) throws SQLException {
        //1.調(diào)用方法獲取PreparedStatement對象(已經(jīng)給?完成了賦值)
        PreparedStatement pstmt = HMQueryRunnerUtils.preparedStatement(con, sql, params);
        //5.執(zhí)行查詢
        int result = pstmt.executeUpdate();
        //6.返回結(jié)果
        return result;
    }

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

    //執(zhí)行查詢
    public <T> T query(Connection con, String sql, HMResultSetHandler<T> hmrsh, Object ... params) throws SQLException {
        //1.調(diào)用方法,執(zhí)行查詢
        ResultSet rs = HMQueryRunnerUtils.getResultSet(con, sql, params);
        //2.調(diào)用結(jié)果集處理器的handler方法,處理結(jié)果集
        T t = hmrsh.handler(rs);
        //返回結(jié)果對象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 {
    //構(gòu)造方法private修飾
    private HMQueryRunnerUtils(){}
    //靜態(tài)方法,獲取PreparedStatement對象
    public static PreparedStatement preparedStatement(Connection con, String sql, Object ... params) throws SQLException {
        //1.獲取執(zhí)行sql語句的PreparedStatement對象
        PreparedStatement pstmt = con.prepareStatement(sql);
        //2.獲取sql語句參數(shù)的ParameterMetaData對象
        ParameterMetaData pmd = pstmt.getParameterMetaData();
        //3.獲取sql語句中?的數(shù)量
        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;
    }
    //執(zhí)行查詢獲取結(jié)果集
    public static ResultSet getResultSet(Connection con, String sql, Object ... params) throws SQLException {
        //1.調(diào)用方法獲取PreparedStatement對象(已經(jīng)給?完成了賦值)
        PreparedStatement pstmt = preparedStatement(con, sql, params);
        //2.執(zhí)行查詢
        ResultSet rs = pstmt.executeQuery();
        //3.返回結(jié)果集
        return rs;
    }
    public static <T> T getInstance(ResultSet rs,Class<T> clazz, ResultSetMetaData rmd, int count) throws InstantiationException, IllegalAccessException, SQLException, NoSuchMethodException, ClassNotFoundException, InvocationTargetException {
        //6.反射創(chuàng)建對象
        T t = clazz.newInstance();
        //7.獲取所以字段名,調(diào)用set方法完成對象的賦值
        for (int i = 0; i < count; i++) {
            String columnName = rmd.getColumnName(i + 1);
            //8.調(diào)用方法,根據(jù)字段名獲取對應(yīng)的set方法名稱
            String setMethodName = getSetMethodName(columnName);
            //9.獲取列類型對應(yīng)的java類型的全類名
            String columnClassName = rmd.getColumnClassName(i + 1);

            //9.反射獲取set方法對象
            Method setMethod = clazz.getMethod(setMethodName, Class.forName(columnClassName));
            //10.執(zhí)行set方法對象,給屬性賦值
            setMethod.invoke(t,rs.getObject(i+1));
        }
        return t;
    }

    //根據(jù)字段名稱,獲取對應(yīng)的Set方法名稱
    private static String getSetMethodName(String fieldName) {
        return "set".concat(fieldName.substring(0,1).toUpperCase().concat(fieldName.substring(1)));
    }
}

  1.2.1 構(gòu)造方法使用-提供數(shù)據(jù)源

  構(gòu)造方法

  `HMQueryRunner(DataSource) ` 創(chuàng)建核心類,并提供數(shù)據(jù)源,內(nèi)部自己維護Connection

  普通方法

  `update(String sql , Object ... params) ` 執(zhí)行DML語句

  `query(String sql , HMResultSetHandler , Object ... params) ` 執(zhí)行DQL語句,并將查詢結(jié)果封裝到對象中。

  1.2.2 構(gòu)造方法使用-不提供數(shù)據(jù)源

  構(gòu)造方法

  `HMQueryRunner()` 創(chuàng)建核心類,**沒有**提供數(shù)據(jù)源,在進(jìn)行具體操作時,需要手動提供Connection

  普通方法

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

  `query(Connection conn , String sql , HMResultSetHandler , Object ... params) ` 使用提供的Connection,執(zhí)行DQL語句,并將查詢結(jié)果封裝到對象中。

  1.3 結(jié)果集處理器接口HMResultSetHandler源代碼

  ```java

package com.itheima.dbutils.inter;

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

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

  1.4 結(jié)果集處理器接口實現(xiàn)類

  HMBeanHandler:將結(jié)果集中第一條記錄封裝到一個指定的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.獲取結(jié)果集元數(shù)據(jù)
            ResultSetMetaData rmd = rs.getMetaData();
            //4.獲取列數(shù)量
            int count = rmd.getColumnCount();
            //5.處理結(jié)果集
            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:將結(jié)果集中每一條記錄封裝到指定的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;
    //構(gòu)造方法
    public HMBeanListHandler(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public List<T> handler(ResultSet rs) throws SQLException {
        //2.創(chuàng)建List集合對象
        List<T> list = new ArrayList<>();
        try {
            //3.獲取結(jié)果集元數(shù)據(jù)
            ResultSetMetaData rmd = rs.getMetaData();
            //4.獲取列數(shù)量
            int count = rmd.getColumnCount();
            //5.處理結(jié)果集
            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:它是用于單數(shù)據(jù)。例如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.處理結(jié)果集
        if(rs.next()) {
            if(columnName == null) {
                t = (T)rs.getObject(columnIndex);
            } else {
                t = (T)rs.getObject(columnName);
            }

        }
        return t;

    }
}

  HMColumnListHandler:將結(jié)果集中指定的列的字段值,封裝到一個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.創(chuàng)建List集合對象
        List<T> list = new ArrayList<>();

        //3.獲取結(jié)果集元數(shù)據(jù)
        ResultSetMetaData rmd = rs.getMetaData();
        //4.獲取列數(shù)量
        int count = rmd.getColumnCount();
        //5.處理結(jié)果集
        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包,就可以通過導(dǎo)入jar包的方式進(jìn)行使用了(本文檔提供打好的jar包)

  關(guān)于如何把idea中模塊打成jar包,這里就不再詳細(xì)描述,可以百度搜索: idea中如何將代碼打成jar包

1657076346085_idea中如何將代碼打成jar包.jpg

  總結(jié)

  1.此篇文章用來模擬DBUtils簡化JDBC操作數(shù)據(jù)庫的復(fù)雜步驟

  2.大量使用反射,讓代碼更為靈活,使用者更加方便

  3.方法參數(shù)是接口,調(diào)用者可以根據(jù)需求傳遞具體的實現(xiàn)了,如果感覺實現(xiàn)類不合適,可以自己定義實現(xiàn)類,提高了代碼的擴展性

分享到:
在線咨詢 我要報名
和我們在線交談!