【JDBC】工具类封装_baseDao概念

一、引入

我们刚刚完成了JDBC第一个版本和第二个版本的封装,但是这两个版本只是优化了JDBC操作中的某几步(下图中的1、2、8步)。

下面会使用BaseDao将3、4、5、6、7步优化。

我们后期,基本上每一个数据表都应该有一个对应的 DAO 接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以可以抽取公共代码,给这些 DAO 的实现类可以抽取一个公共的父类,我们称为 BaseDao

image-20240726111908900

二、非DQL方法封装

package com.atguigu.api.utils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;

/**
 * 封装Dao数据库重复代码!
 * TODO:
 *  封装两个方法  一个简化非DQL
 *              一个简化DQL
 *
 *              List<Object> params
 */

public class BaseDao {
    /**
     * 封装简化非SQL 语句
     * @param sql   带占位符的SQL语句
     * @param params    占位符的值   PS:传入占位符的值,必须等于SQL语句?位置!
     * @return  执行影响的行数
     */
    public int executeUpdate(String sql, Objects... params) throws Exception {//可变参数必须存在于形参列表的最后一位
        //获取连接
        Connection connection = JdbcUtilsV2.getConnection();

        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //5.占位符赋值
        //可变参数可以当数组使用
        for (int i = 1; i <= params.length; i++) {
            preparedStatement.setObject(i, params[i - 1]);
        }

        int rows = preparedStatement.executeUpdate();

        preparedStatement.close();
        //是否回收连接,需要考虑是不是事务
        if (connection.getAutoCommit()) {
            //没有开启事务
            //没有开启事务 正常回收连接!
            JdbcUtilsV2.freeConnection();
        }
//        connection.setAutoCommit(false);//开启事务了 不要管连接即可! 由业务层来处理

        return rows;
    }
}

使用代码:

package com.atguigu.api.utils;

import org.junit.Test;
import java.sql.*;
import java.util.*;

public class PSCURDPart extends BaseDao{
    @Test
    public void testInsert() throws ClassNotFoundException, SQLException {
        String sql = "insert into employee(id, salary) values(?, ?);";

        int rows = executeUpdate(sql, 1, 111);
    }
}

三、DQL查询方法封装

DQL的封装要比非DQL封装更难一些

1)思路

非DQL语句封装方法 ->返回值固定为int
DQL语句封装方法 -> 返回值是什么类型呢?
     DQL -> 返回结果是List<Map> -> 也就是说我将一行数据装到Map对象,因为有多行数据,所以最终要返回 List<Map>
     but,我们的返回值并不是List<Map>, 不是说这个类型不能用,是它不好用,map里面的数据有先天的优势,key 和 value都是自定义的,不用先设定好
                 但是map是没有数据校验机制的,例如我往Map中传年龄,传的是-1,那么Map中存的就是-1
                 而且Map也不支持反射操作
        实际上:  数据库中的数据 都会对应到java的实体类
        数据库中的表中的一行数据等于 java类中的一个对象,多行数据可以等于Java实体类中的集合,这样的做法其实就是面向对象的一种思维了
所以DQL语句返回值应该为某一个类型的实体类集合 List<T> list
<T> 声明一个方法泛型,不确定类型,此时我们就可以让对方传一个class对象,这个方法的好处有两点
         1.确定泛型 如果你传入的是User.class,那么 T = User
         2.后期要使用反射技术为属性赋值
public <T>  List<T> executeQuery(Class<T> clazz, String sql, Object... params);

2)代码示例

/**
 * 将查询结果封装到一个实体类集合!
 *
 * @param clazz  要接值的实体类集合的模板对象
 * @param sql    查询语句,要求列名或者别名等于实体类的属性名!如果不等于,那就起别名
 * @param params 占位符的值,要和?位置对象传递
 * @param <T>    声明的结果的泛型
 * @return 查询的实体类集合
 * @throws Exception
 */
public <T> List<T> executeQuery(Class<T> clazz, String sql, Object... params) throws Exception {
    //获取连接
    Connection connection = JdbcUtilsV2.getConnection();

    PreparedStatement preparedStatement = connection.prepareStatement(sql);

    if (params != null && params.length != 0) {
        for (int i = 1; i <= params.length; i++) {
            preparedStatement.setObject(i, params[i - 1]);
        }
    }

    ResultSet resultSet = preparedStatement.executeQuery();

    List<T> list = new ArrayList<>();

    //TODO:metaData 装的当前 结果集 列的信息对象!(他可以获取列的名称 根据下角标,可以获取列的数量)
    ResultSetMetaData metaData = resultSet.getMetaData();

    //有了它以后,我们可以水平遍历列!
    int columnCount = metaData.getColumnCount();

    //一行数据对应一个 T 类型的对象
    while (resultSet.next()) {
        T t = clazz.newInstance();//调用类的无参构造函数实例化对象!

        for (int i = 1; i <= columnCount; i++) {
            //对象的属性值
            Object value = resultSet.getObject(i);

            //对象的属性名
            String propertyName = metaData.getColumnLabel(i);

            //反射给对象的属性值
            Field field = clazz.getDeclaredField(propertyName);
            field.setAccessible(true);//属性可以设置,打破private的修饰限制
            /**
             * 参数1:要赋值的对象 如果属性是静态属性,第一个参数可以为null!
             * 参数2:具体的属性值
             */
            field.set(t, value);
        }
        // 一行数据的所有列全部存到了Map中,然后将Map存到集合中即可
        list.add(t);
    }

    //关闭资源
    resultSet.close();
    preparedStatement.close();
    if (connection.getAutoCommit()) {
        //没有事务,可以关闭
        JdbcUtilsV2.freeConnection();
    }

    return list;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值