更新時間:2022-07-06 來源:黑馬程序員 瀏覽量:
1.1 概述
如果只使用JDBC進行開發(fā),冗余代碼過多,為了簡化JDBC開發(fā)。我們采用apache commons組件一個成員:DBUtils。
DBUtils就是JDBC的簡化開發(fā)工具包。需要項目導入commons-dbutils-1.6.jar才能夠正常使用DBUtils工具。
DBUtils是java編程中的數(shù)據(jù)庫操作實用工具,小巧簡單實用。DBUtils封裝了對JDBC的操作,簡化了JDBC操作,可以少寫代碼。
本案例就是模擬DBUtils的功能自定義一個簡化JDBC開發(fā)的工具HMDButils,目的練習反射的內(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ù)源,在進行具體操作時,需要手動提供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包,就可以通過導入jar包的方式進行使用了(本文檔提供打好的jar包)
關(guān)于如何把idea中模塊打成jar包,這里就不再詳細描述,可以百度搜索: idea中如何將代碼打成jar包

總結(jié)
1.此篇文章用來模擬DBUtils簡化JDBC操作數(shù)據(jù)庫的復雜步驟
2.大量使用反射,讓代碼更為靈活,使用者更加方便
3.方法參數(shù)是接口,調(diào)用者可以根據(jù)需求傳遞具體的實現(xiàn)了,如果感覺實現(xiàn)類不合適,可以自己定義實現(xiàn)類,提高了代碼的擴展性