一. 分析
由上一篇Day3_JDBC——使用DBUtils第三方工具完成增删改查的封装(BaseDao类)可知,BaseDao类中的每一个方法,都需要传入一个实体类的类型(即JavaBean类型)。假如我们在继承BaseDao类的时候,直接告诉BaseDao的构造器我的实体类的类型,这样就再也不用在方法里面传入一个实体类的类型。
二. 例子
本项目的目录结构如下:
BaseDao2.java
package com.atguigu.dao;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import com.atguigu.utils.JDBCUtils;
public class BaseDao2<T> {
private QueryRunner runner = new QueryRunner();
private Class<T> type;//目的是将T赋给type,即要把BaseDao2的泛型拿到,交给type
/*
* 在无参构造器中获取类泛型的类型,BaseDao2不会直接创建对象
* BaseDao2构造器中this代表子类对象
*/
public BaseDao2() {
//1.获取子类对象的类模板, UserDao2 extends BaseDao2<User>
Class<? extends BaseDao2> cla = this.getClass();
//2.获取父类的带泛型的类型
//cla.getSuperclass();获取父类类型 BaseDao2
ParameterizedType pt = (ParameterizedType) cla.getGenericSuperclass();//获取真实的父类类型BaseDao2<User>
//3.获取泛型列表,一个类可以声明多个泛型参数Map<K,V>
Type[] types = pt.getActualTypeArguments();
//4.取出第一位的泛型就是BaseDao2的泛型类型
type = (Class<T>) types[0];
}
//增删改
public int update(String sql, Object...params) {
Connection conn = JDBCUtils.getConn();
int count = 0;
try {
count = runner.update(conn, sql, params);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.closeConn(conn);
}
return count;
}
//查询一条记录封装为对象的方法
public T getBean( String sql, Object...params){
Connection conn = JDBCUtils.getConn();
T t = null;
try {
//BeanHandler将查询到的记录封装为一个对象
//type类中必须由无参构造器,type类的属性名必须和sql查询的列名一致
t = runner.query(conn, sql, new BeanHandler<>(type), params);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("t为:" + t);
}finally {
JDBCUtils.closeConn(conn);
}
return t;
}
//查询多条记录并封装为对象的集合
public List<T> getBeanList( String sql, Object...params){
Connection conn = JDBCUtils.getConn();
List<T> list = null;
try {
list = runner.query(conn, sql, new BeanListHandler<>(type), params);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.closeConn(conn);
}
return list;
}
//查询数据库表的总记录条数,可变参数列表是0个~n个参数,
//如果没有参数,则不需要传入可变参数列表,连null也不用传
public long getCount(String sql, Object...params) {
Connection conn = JDBCUtils.getConn();
//ScalarHandler:无参构造器默认将查询到的第一行第一列数据封装为对象返回
// 如果是整数类型返回真实类型Long
// 如果真实返回类型是String,并提升为Object返回
long count = 0;
try {
count = (long) runner.query(conn, sql, new ScalarHandler(), params);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.closeConn(conn);
}
return count;
}
//批量增删改,它需要知道执行多少次,每次的参数是什么
//所以方法中的二维数据参数,第一维代表批处理执行的次数
//第二维代表每次批处理需要的参数列表
public void batchUpdate(String sql, Object[][] params) {
Connection conn = JDBCUtils.getConn();
try {
runner.batch(conn, sql, params);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.closeConn(conn);
}
}
}