更新时间: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.方法参数是接口,调用者可以根据需求传递具体的实现了,如果感觉实现类不合适,可以自己定义实现类,提高了代码的扩展性