更新时间: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包
总结
1.此篇文章用来模拟DBUtils简化JDBC操作数据库的复杂步骤
2.大量使用反射,让代码更为灵活,使用者更加方便
3.方法参数是接口,调用者可以根据需求传递具体的实现了,如果感觉实现类不合适,可以自己定义实现类,提高了代码的扩展性