⛳ 一个通用的数据库操作类

⛳ 一个通用的数据库操作类

该数据库操作类较为偏向底层,除基本的JDBC的操作外,还结合了 反射泛型 的知识,里边编写了对数据库的更新、删除、插入、普通查询、复杂查询等操作,是一个通用的数据库操作类。

🎁 代码:

package asia.mrgu.myssm.basedao;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseDao<T> {

    public final String DRIVER = "com.mysql.cj.jdbc.Driver";
    public final String URL = "jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC";
    public final String USER = "root";
    public final String PWD = "1234";

    protected Connection conn;
    protected PreparedStatement ps;
    protected ResultSet rs;


    // T的Class对象
    private Class entityClass;

    public BaseDao() {
        // getClass() 获取Class对象,当前我们执行的是new FruitDaoImpl() ,创建的是FruitDaoImpl的实例
        // 那么子类构造方法内部首先会调用父类 (BaseDao)的无参构造方法
        // 因此此处的getClass() 会被执行,但是getClass获取的是FruitDaoImpl的Class
        // 所以getGenericSuperclass()获取到的是BaseDao的class
        /**
         * getClass().getGenericSuperclass() 是一个 Java 反射 API,用于获取当前类的直接超类的 Type。它返回一个表示当前类的直接超类的 Type 对象。如果当前类没有超类,则返回 Object.class。需要注意的是,如果当前类是接口,则该方法返回的 Type 对象表示该接口的直接超接口。
         */
        Type generictype = getClass().getGenericSuperclass();
        // ParameterType 参数化类型
        Type[] actualTypeArguments = ((ParameterizedType) generictype).getActualTypeArguments();
        // 获取到的 <T> 中的 T 的真实的类型
        Type actualType = actualTypeArguments[0];
        try {
            entityClass = Class.forName(actualType.getTypeName());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    protected Connection getConn() {
        try {
            // 1、加载驱动
            Class.forName(DRIVER);
            // 2、通过驱动管理器获取链接对象
            return DriverManager.getConnection(URL, USER, PWD);
        } catch (ClassNotFoundException | SQLException e) {
            throw new RuntimeException(e);
        }
    }

    protected void close(ResultSet rs, PreparedStatement ps, Connection conn) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            if (conn != null && !conn.isClosed()) {
                conn.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    // 给预处理命令对象设置参数
    private void setParams(PreparedStatement ps, Object... params) throws SQLException {
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
        }
    }

    // 执行更新,返回影响行数
    protected int executeUpdate(String sql, Object... params) {
        boolean insertFlag = false;
        /**
         * trim() 方法可以去除字符串两端的空格,返回一个新的字符串。
         * toUpperCase() 方法可以将字符串全部转换为大写字母,返回一个新的字符串。
         * startsWith("INSERT") 方法可以检查当前字符串是否以 "INSERT" 开头,返回一个布尔值。
         */
        insertFlag = sql.trim().toUpperCase().startsWith("INSERT");

        try {
            conn = getConn();
            if (insertFlag) {
                /**
                 * 创建一个PreparedStatement对象,并指定了一个参数Statement.RETURN_GENERATED_KEYS
                 * ,表示希望在执行SQL语句后返回自动生成的主键值。
                 * 在执行插入操作时,如果表中的主键是自动生成的(例如使用 AUTO_INCREMENT 关键字),
                 * 则可以使用 Statement.RETURN_GENERATED_KEYS 参数来获取插入后自动生成的主键值。
                 */
                ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            } else {
                ps = conn.prepareStatement(sql);
            }
            setParams(ps, params);
            int count = ps.executeUpdate();

            if (insertFlag) {
                /**
                 * 插入成功后,可以通过 ps.getGeneratedKeys() 方法获取自动生成的主键值的结果集,
                 * 然后通过 rs.getInt(1) 方法获取主键值。
                 */
                rs = ps.getGeneratedKeys();
                if (rs.next()) {
                    return ((Long) rs.getLong(1)).intValue();
                }
            }
            return count;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, ps, conn);
        }
    }

    // 通过反射技术给obj对象的property属性赋propertyValue值
    private void setValue(Object obj, String property, Object propertyValue) {
        Class<?> aClass = obj.getClass();
        try {
            // 获取property这个字符串对应的属性名,比如,"fid" 去找obj对象中的fid属性
            /**
             * 调用clazz.getDeclaredField(property)方法获取到属性名为property的Field对象,如果该属性不存在则返回null。
             */
            Field field = aClass.getDeclaredField(property);
            if (field != null) {
                /**
                 * 调用field.setAccessible(true)方法将该Field对象设置为可访问状态,以便在后续操作中可以访问该属性。
                 * 如果属性的访问权限为private,需要通过setAccessible方法将其设置为可访问状态才能够进行操作。
                 */
                field.setAccessible(true);
                /**
                 * 调用field.set(obj, propertyValue)方法将obj对象的属性值设置为propertyValue。
                 */
                field.set(obj, propertyValue);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    // 执行复杂查询,返回例如统计结果
    protected Object[] executeComplexQuery(String sql, Object... params) {
        try {
            conn = getConn();
            ps = conn.prepareStatement(sql);
            setParams(ps,params);
            rs = ps.executeQuery();

            // 通过rs可以获取结果集的元数据
            // 元数据:描述结果集数据的数据,简单讲,就是这个结果集有哪些列,什么类型等
            ResultSetMetaData metaData = rs.getMetaData();

            // 获取结果集的列数
            int columnCount = metaData.getColumnCount();
            /**
             * 定义了一个 Object 类型的数组 columnValueArr,数组的长度为 columnCount。该数组用于存储数据库表中一行数据的所有列的值,每个列的值都是一个 Object 类型的对象。通常在使用 JDBC 连接数据库时,通过查询 ResultSet 对象获取到一行数据的所有列的值,然后将这些值存储到一个数组中方便后续处理。
             */
            Object[] columnValueArr = new Object[columnCount];
            // 解析rs
            if (rs.next()){
                for (int i = 0; i < columnCount; i++) {
                    /**
                     * rs.getObject方法的列索引是从1开始的,而不是从0开始。
                     */
                    Object columnValue = rs.getObject(i + 1);
                    columnValueArr[i] = columnValue;
                }
                return columnValueArr;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs,ps,conn);
        }
        return null;
    }

    // 执行查询,返回单个实体对象
    protected T load(String sql , Object... params){
        try {
            conn = getConn();
            ps = conn.prepareStatement(sql);
            setParams(ps,params);
            rs = ps.executeQuery();

            // 通过rs可以获取结果集的元数据
            // 元数据:描述结果集数据的数据,简单讲,就是这个结果集有哪些列,什么类型等

            ResultSetMetaData metaData = rs.getMetaData();
            // 获取结果集的列数
            int columnCount = metaData.getColumnCount();
            // 解析rs
            if (rs.next()){
                T entity = (T)entityClass.newInstance();

                for (int i = 0; i < columnCount; i++) {
                    String columnName = metaData.getColumnName(i + 1);
                    Object columnValue = rs.getObject(i + 1);
                    setValue(entity,columnName,columnValue);
                }
                return entity;
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    // 执行查询,返回 List
    protected List<T> executeQuery(String sql, Object... params){
        List<T> list = new ArrayList<>();
        try {
            conn = getConn();
            ps = conn.prepareStatement(sql);
            setParams(ps,params);
            rs = ps.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等

            ResultSetMetaData metaData = rs.getMetaData();
            // 获取结果集的列数
            int columnCount = metaData.getColumnCount();
            // 解析rs
            while (rs.next()){
                T entity = (T)entityClass.newInstance();

                for (int i = 0; i < columnCount; i++) {
                    String columnName = metaData.getColumnName(i + 1);
                    Object columnValue = rs.getObject(i + 1);
                    setValue(entity,columnName,columnValue);
                }
                list.add(entity);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return list;
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值