从JDBC到手撸极简版Mybaties(2)JDBC封装

简介

上篇文章大致写了JDBC连接数据库的步骤,可是每次都这么来一遍,着实麻烦。所以我们干脆把它封装起来。以后要用直接调用即可啦。

代码实现

1、加载驱动的封装

对于驱动加载,我们从头到尾只用执行一次。所以,我们可以模仿别人的写法把它放在静态代码块里面:

public class DBUtil {
    private static final String DB_DEIVER = "com.mysql.jdbc.Driver";
    private static final String DB_URL = "jdbc:mysql://my.mcdd.top:3306/test";
    private static final String DB_USER = "root";
    private static final String DB_PWD = "m147258369";
    private static Connection connection;

    /**
     * 加载驱动
     */
    static {
        try {
            Class.forName(DB_DEIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}

2、连接数据库封装

对于连接数据库,我们不要一开始就连接上了,因为那样太耗费资源了。所以可以封装成函数,然后在构造函数传值之后调用,这样每次new对象的时候,就会自动连接数据库啦。
连接数据库代码:

    /**
     * 连接数据库
     */
    public void getConnection(){
        try {
            connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    public void getConnection(String url, String user, String pwd){
        try {
            connection = DriverManager.getConnection(url, user, pwd);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

哈哈,当然是俩份啦,传参就用传入值,不传的话,就用默认值。
然后编写构造函数:

    /**
     * 构造函数
     */
    public DBUtil() {
        getConnection();
    }
    public DBUtil(String url, String user, String pwd) {
        getConnection(url, user, pwd);
    }

同样俩份。

3、查询语句封装

思路:从数据库拿到值之后,利用反射创建实体类,然后进行属性赋值。

    /**
     * 查询语句封装,返回值根据实体类成员名称进行赋值
     * @param sql sql语句
     * @param args 参数,用List传
     * @param tClass 返回值列表里的成员类型
     * @return 返回查询结果的List
     */
    public <T> List<T>  selectResultByName(String sql, List<?> args, Class<T> tClass){
        List<T> resList = new ArrayList<>();
        try {
            // 利用反射获取属性
            Field[] declaredFields = tClass.getDeclaredFields();
            // 创建语句
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 赋值参数
            for (int i = 0; i < args.size(); i++) {
                preparedStatement.setObject(i+1, args.get(i));
            }
            // 执行语句
            ResultSet resultSet = preparedStatement.executeQuery();
            // 获取返回值的表数据和它的长度
            ResultSetMetaData metaData = resultSet.getMetaData();
            while (resultSet.next()) {
                // 反射构建类
                Object res = tClass.getDeclaredConstructor().newInstance();
                for (Field declaredField : declaredFields) {
                    Object object = resultSet.getObject(declaredField.getName());
                    declaredField.setAccessible(true);
                    declaredField.set(res, object);
                }
                resList.add((T) res);
            }
            preparedStatement.close();
            resultSet.close();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return resList;
    }

这里要注意的是,我们采用的赋值方法是从传入类型的成员变量中拿到属性名,再用这个属性名去找result中的对应值,最后赋值。

但是也有一种可能,数据库的值和实体类对不上,我们赋值采用顺序赋值,所以:

    /**
     * 查询语句封装,返回值根据实体类成员顺序进行赋值
     * @param sql sql语句
     * @param args 参数,用List传
     * @param tClass 返回值列表里的成员类型
     * @return 返回查询结果的List
     */
    public <T> List<T>  selectResultByOrder(String sql, List<?> args, Class<T> tClass){
        List<T> resList = new ArrayList<>();
        int columLen;
        try {
            // 利用反射获取属性
            Field[] declaredFields = tClass.getDeclaredFields();

            // 创建语句
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 赋值参数
            for (int i = 0; i < args.size(); i++) {
                preparedStatement.setObject(i+1, args.get(i));
            }
            // 执行语句
            ResultSet resultSet = preparedStatement.executeQuery();
            // 获取返回值的表数据和它的长度
            ResultSetMetaData metaData = resultSet.getMetaData();
            columLen = metaData.getColumnCount();
            while (resultSet.next()) {
                // 反射构建类
                Object res = tClass.getDeclaredConstructor().newInstance();
                // 遍历resultSet的每个属性值
                for (int i = 0; i < columLen; i++) {
                    // 获取每一个返回对象的参数名
                    String columnName = metaData.getColumnName(i + 1);
                    // 获取对应名的参数
                    Object object = resultSet.getObject(columnName);
                    // 利用反射给res赋值参数
                    declaredFields[i].setAccessible(true);
                    declaredFields[i].set(res, object);
                }
                resList.add((T) res);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return resList;
    }

关闭连接

这个简单:

    /**
     * 关闭连接
     */
    public void close(){
        try {
            connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

最后

最后贴上我们最终的代码:

package com.sy;

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

/**
 * @author :byMJC
 * @date :Created 2022/1/14 20:48
 * @description:my DBUtil
 */

public class DBUtil {
    private static final String DB_DEIVER = "com.mysql.jdbc.Driver";
    private static String DB_URL = "jdbc:mysql://my.mcdd.top:3306/test";
    private static String DB_USER = "root";
    private static String DB_PWD = "m147258369";
    private static Connection connection;

    /**
     * 加载驱动
     */
    static {
        try {
            Class.forName(DB_DEIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接数据库
     */
    public void getConnection(String url, String user, String pwd){
        try {
            connection = DriverManager.getConnection(url, user, pwd);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    /**
     * 构造函数
     */
    public DBUtil() {
        getConnection(DB_URL, DB_USER, DB_PWD);
    }
    public DBUtil(String url, String user, String pwd) {
        DB_URL = url;
        DB_USER = user;
        DB_PWD = pwd;
        getConnection(DB_URL, DB_USER, DB_PWD);
    }

    /**
     * 查询语句封装,返回值根据实体类成员顺序进行赋值
     * @param sql sql语句
     * @param args 参数,用List传
     * @param tClass 返回值列表里的成员类型
     * @return 返回查询结果的List
     */
    public <T> List<T>  selectResultByOrder(String sql, List<?> args, Class<T> tClass){
        List<T> resList = new ArrayList<>();
        int columLen;
        try {
            if (connection.isClosed()) {
                getConnection(DB_URL, DB_USER, DB_PWD);
            }
            // 利用反射获取属性
            Field[] declaredFields = tClass.getDeclaredFields();

            // 创建语句
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 赋值参数
            for (int i = 0; i < args.size(); i++) {
                preparedStatement.setObject(i+1, args.get(i));
            }
            // 执行语句
            ResultSet resultSet = preparedStatement.executeQuery();
            // 获取返回值的表数据和它的长度
            ResultSetMetaData metaData = resultSet.getMetaData();
            columLen = metaData.getColumnCount();
            while (resultSet.next()) {
                // 反射构建类
                Object res = tClass.getDeclaredConstructor().newInstance();
                // 遍历resultSet的每个属性值
                for (int i = 0; i < columLen; i++) {
                    // 获取每一个返回对象的参数名
                    String columnName = metaData.getColumnName(i + 1);
                    // 获取对应名的参数
                    Object object = resultSet.getObject(columnName);
                    // 利用反射给res赋值参数
                    declaredFields[i].setAccessible(true);
                    declaredFields[i].set(res, object);
                }
                resList.add((T) res);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return resList;
    }


    /**
     * 查询语句封装,返回值根据实体类成员名称进行赋值
     * @param sql sql语句
     * @param args 参数,用List传
     * @param tClass 返回值列表里的成员类型
     * @return 返回查询结果的List
     */
    public <T> List<T>  selectResultByName(String sql, List<?> args, Class<T> tClass){

        List<T> resList = new ArrayList<>();
        try {
            if (connection.isClosed()) {
                getConnection(DB_URL, DB_USER, DB_PWD);
            }
            // 利用反射获取属性
            Field[] declaredFields = tClass.getDeclaredFields();

            // 创建语句
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 赋值参数
            for (int i = 0; i < args.size(); i++) {
                preparedStatement.setObject(i+1, args.get(i));
            }
            // 执行语句
            ResultSet resultSet = preparedStatement.executeQuery();
            // 获取返回值的表数据和它的长度
            ResultSetMetaData metaData = resultSet.getMetaData();
            while (resultSet.next()) {
                // 反射构建类
                Object res = tClass.getDeclaredConstructor().newInstance();
                for (Field declaredField : declaredFields) {
                    Object object = resultSet.getObject(declaredField.getName());
                    declaredField.setAccessible(true);
                    declaredField.set(res, object);
                }
                resList.add((T) res);
            }
            preparedStatement.close();
            resultSet.close();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return resList;
    }

    /**
     * 关闭连接
     */
    public void close(){
        try {
            connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

}

代码和之前的又有一点点不同,因为我们还要考虑到一种情况,如果用户已经关闭连接了,但是又要进行数据库操作了怎么办?所以我在每条语句前面都加了个检测数据库连接,并且自动连接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值