尚硅谷之JDBC

1.4 抽取BasicDAO

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;

    }

}

 

 


上一篇:
下一篇:
关于尚硅谷
教育理念
名师团队
学员心声
资源下载
视频下载
资料下载
工具下载
加入我们
招聘岗位
岗位介绍
招贤纳师
联系我们
电话:010-56253825
邮箱:info@atguigu.com
地址:北京市昌平区宏福科技园综合楼6层(北京校区)

 深圳市宝安区西部硅谷大厦B座C区一层(深圳校区)

上海市松江区谷阳北路166号大江商厦6层(上海校区)