package com.atguigu.dao.impl;
/* * 这个类的作用是:对DAOImpl再次抽象,把共同的部分再次抽取 */ import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;
import com.atguigu.utils.JDBCUtils;
//泛型类 public abstract class BasicDAOImpl<T> { private Class<T> type;
@SuppressWarnings("all") protected BasicDAOImpl() { // 为什么要在构造器中写,因为子类继承BasicDAOImpl类一定会调用父类的构造器 Class clazz = this.getClass();// this代表的是正在创建的那个对象,即子类的对象
// 获取clazz的带泛型父类信息 Type superType = clazz.getGenericSuperclass();
// Father<String>:参数化的类型 ParameterizedType p = (ParameterizedType) superType;
// 获取泛型实参 Type[] ts = p.getActualTypeArguments();
// 因为当前类只有一个泛型形参,即子类中只有一个泛型实参 type = (Class) ts[0]; }
protected int update(String sql, Object... params) throws SQLException { //1、获取连接 Connection conn = JDBCUtils.getConnection(); //2、执行更新数据库语句 int len = executeUpdate(conn, sql, params); //3、关闭连接 JDBCUtils.closeQuietly(conn); return len; }
// 如果有需要在一个事务中完成更新,可以调用这个带conn的方法 protected int update(Connection conn, String sql, Object... params) throws SQLException { //执行更新数据库语句 int len = executeUpdate(conn, sql, params); return len; }
private int executeUpdate(Connection conn, String sql, Object... params) throws SQLException { //1、sql预编译 PreparedStatement pst = conn.prepareStatement(sql);
//2、设置sql中的? if (params != null && params.length > 0) { // 数组的下标是从0开始,?的编号是1开始 for (int i = 0; i < params.length; i++) { pst.setObject(i + 1, params[i]); } }
//3、执行sql int len = pst.executeUpdate();
//4、释放资源 JDBCUtils.closeQuietly(pst); return len; }
//通用的查询方法之一:查询一行,即一个对象 /** * 执行查询操作的SQL语句,SQL可以带参数(?) * @param sql String 执行查询操作的SQL语句 * @param args Object... 对应的每个?设置的值,顺序要与?对应 * @return T 封装了查询结果的实体 * @throws Exception */ protected T get(String sql, Object... params) throws Exception { //1、获取连接 Connection conn = JDBCUtils.getConnection();
//2、执行查询语句 ResultSet rs = executeQuery( conn,sql, params);
//3、处理查询结果 //(1)获取查询的结果集的元数据信息 ResultSetMetaData rsmd = rs.getMetaData();
//(2)这是查询的结果集中,一共有几列 int count = rsmd.getColumnCount();
//(3)创建实例对象 T t = type.newInstance();// 要求这个Javabean类型必须有无参构造
//(4)遍历结果集 while (rs.next()) { /* * 问题? (1)sql语句中查询了几列,每一列是什么属性 (2)怎么把这个值设置到Javabean的属性中 */ // (5)循环每一行有几列 for (int i = 0; i < count; i++) { // (6)获取第几列的名称 // String columnName = rsmd.getColumnName(i+1); // 如果sql中没有取别名,那么就是列名,如果有别名,返回的是别名 String fieldName = rsmd.getColumnLabel(i + 1);
// (7)获取该列的值 // Object value = rs.getObject(columnName); Object value = rs.getObject(fieldName);
// (8)设置obj对象的某个属性中 Field field = type.getDeclaredField(fieldName);// JavaBean的属性名 field.setAccessible(true); field.set(t, value); } }
//4、释放资源 JDBCUtils.closeQuietly(rs); JDBCUtils.closeQuietly(conn);
return t; }
private static ResultSet executeQuery(Connection conn, String sql, Object... params) throws SQLException { //1、sql预编译 PreparedStatement pst = conn.prepareStatement(sql);
//2、设置? if (params != null && params.length > 0) { // 数组的下标是从0开始,?的编号是1开始 for (int i = 0; i < params.length; i++) { pst.setObject(i + 1, params[i]); } }
//3、查询 ResultSet rs = pst.executeQuery(); return rs; }
// 通用的查询方法之二:查询多行,即多个对象 // Class<T> clazz:用来创建实例对象,获取对象的属性,并设置属性值 /** * 执行查询操作的SQL语句,SQL可以带参数(?) * @param sql String 执行查询操作的SQL语句 * @param args Object... 对应的每个?设置的值,顺序要与?对应 * @return ArrayList<T> 封装了查询结果的集合 * @throws Exception */ public ArrayList<T> getList(String sql, Object... args) throws Exception { // 1、获取连接 Connection conn = JDBCUtils.getConnection();
//2、执行查询sql ResultSet rs = executeQuery(conn,sql, args);
//3、获取结果集的元数据 ResultSetMetaData metaData = rs.getMetaData(); // 获取结果中总列数 int count = metaData.getColumnCount();
// 创建集合对象 ArrayList<T> list = new ArrayList<T>();
while (rs.next()) {// 遍历的行 // 1、每一行是一个对象 T obj = type.newInstance();
// 2、每一行有很多列 // for的作用是为obj对象的每一个属性设置值 for (int i = 0; i < count; i++) { // (1)每一列的名称 String fieldName = metaData.getColumnLabel(i + 1);// 获取第几列的名称,如果有别名获取别名,如果没有别名获取列名 // (2)每一列的值 Object value = rs.getObject(i + 1);// 获取第几列的值 // (3)获取属性对象 Field field = type.getDeclaredField(fieldName); // (4)设置可见性 field.setAccessible(true); // (5)设置属性值 field.set(obj, value); }
// 3、把obj对象放到集合中 list.add(obj); }
// 6、释放资源 JDBCUtils.closeQuietly(rs); JDBCUtils.closeQuietly(conn);
// 7、返回结果 return list; }
//通用的查询方法之三:查询单个值 //单值:select max(salary) from employee; 一行一列 //select count(*) from t_goods; 一共几件商品 public Object getValue(String sql,Object... args)throws Exception{ //1、获取连接 Connection conn = JDBCUtils.getConnection();
//2、执行查询sql ResultSet rs = executeQuery(conn, sql, args);
Object value = null; if(rs.next()){//一行 value = rs.getObject(1);//一列 }
//3、释放资源 JDBCUtils.closeQuietly(rs); JDBCUtils.closeQuietly(conn);
return value; }
//通用的查询方法之四:查询多行多列,但每一行又不是一个JavaBean /* * SELECT did,AVG(salary),MAX(Salary) FROM t_employee GROUP BY did; * did avg(salary) max(salary) 1 1990.90 8900 2 4889 6899 */ public List<Map<String,Object>> getListMap(String sql,Object... args)throws Exception{ //1、获取连接 Connection conn = JDBCUtils.getConnection();
//2、执行sql ResultSet rs = executeQuery(conn, sql, args);
//获取结果集的元数据对象 ResultSetMetaData metaData = rs.getMetaData(); //一共有几列 int count = metaData.getColumnCount(); //创建List ArrayList<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
while(rs.next()){ //每一行是一个Map的对象 HashMap<String,Object> map = new HashMap<String,Object>();
//map的key是列名 for (int i = 0; i < count; i++) { //(1)获取列名或别名 String columnName = metaData.getColumnLabel(i+1); //(2)获取对应的值 Object value = rs.getObject(i+1); //(3)把这对值放到map中 map.put(columnName, value); }
//把map放到List中 list.add(map); }
//6、释放资源 JDBCUtils.closeQuietly(rs); JDBCUtils.closeQuietly(conn);
return list; }
//通用的查询方法之四:查询一行多列,但一行又不是一个JavaBean public Map<String,Object> getMap(String sql,Object... args)throws Exception{ List<Map<String, Object>> listMap = getListMap(sql,args); if(listMap.size()>0){ return listMap.get(0); } return null; } }
|
本教程由尚硅谷教育大数据研究院出品,如需转载请注明来源。