更新時間:2022-07-06 來源:黑馬程序員 瀏覽量:
1.1 概述
如果只使用JDBC進(jìn)行開發(fā),冗余代碼過多,為了簡化JDBC開發(fā)。我們采用apache commons組件一個成員:DBUtils。
DBUtils就是JDBC的簡化開發(fā)工具包。需要項(xiàng)目導(dǎo)入commons-dbutils-1.6.jar才能夠正常使用DBUtils工具。
DBUtils是java編程中的數(shù)據(jù)庫操作實(shí)用工具,小巧簡單實(shí)用。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)部自己維護(hù)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é)果集處理器接口實(shí)現(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包
總結(jié)
1.此篇文章用來模擬DBUtils簡化JDBC操作數(shù)據(jù)庫的復(fù)雜步驟
2.大量使用反射,讓代碼更為靈活,使用者更加方便
3.方法參數(shù)是接口,調(diào)用者可以根據(jù)需求傳遞具體的實(shí)現(xiàn)了,如果感覺實(shí)現(xiàn)類不合適,可以自己定義實(shí)現(xiàn)類,提高了代碼的擴(kuò)展性