• Java -- JDBC学习笔记7、DaoUtils


    1、为什么要封装Dao层工具类?

    在Dao层中,每次对数据库的增、删、改、查操作存在代码冗余,可以将共有代码抽取封装。

    2、哪些代码需要封装?

    • 在修改、删除、添加等操作方法中,每次都需要获取连接对象、获取PreparedStatement、给占位符赋值,释放连接等等。
    • 在查询操作方法中(查询全部和查询所有),也需要获取连接对象,PreparedStatement、ResultSet等对象,还需要循环ResultSet,取值赋值等等。

    3、DaoUtils具体实现

    • 修改、删除、新增使用一个通用方法来实现。
    • 查询单个和查询所有用一个通用方法来实现。

    3.1、增删改通用方法commonsUpdate()

    方法有两个参数,第一个是sql语句、第二个是参数列表。

    • 第二个变量里存放的值是不固定的,因为增删改语句中的参数数量不同,比如:修改需要整张表,删除只需要一个,新增也需要整张表,所以使用Object... args、也就是可变参数。
    • 调用者在调用通用函数、要事先将参数列表定义好,每一个值和sql语句中那一个占位符相对应。
    /**
         * 增删改通用方法
         * @param sql 增删改sql语句
         * @param args 参数列表
         * @return 受影响行数
         */
        public int commonUpdate(String sql, Object... args)
        {
            Connection conn = null;
            PreparedStatement preparedStatement = null;
            try
            {
                conn = DBUtils.getConnection();
                preparedStatement = conn.prepareStatement(sql);
                for (int i = 0; i < args.length; i++)
                {
                    //第一个参数是设置的值下标,从1开始,第二个是从参数列表中取值的下标,所以从0开始
                    preparedStatement.setObject(i + 1, args[i]);
                }
                int result = preparedStatement.executeUpdate();
                return result;
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            finally
            {
                DBUtils.closeDb(null, preparedStatement, null);
            }
            return 0;
        }
    
    • service层调用者、修改数据
    public int update(Account account)
        {
            String sql = "update Account set pwd=?,balance=?,name=? where id=?";
            Object[] arr = {account.getPwd(), account.getBalance(), account.getName(), account.getId()};
            return daoUtils.commonUpdate(sql, arr);
        }
    

    数组里的值和SQL语句中占位符一一对应。

    3.2、查询通用方法commonsSelect()

    查询通用方法相对比较麻烦,因为查询的是单个、还是多个不知道,取值时候也不清楚是哪张表、表中有哪些字段,取出来后赋值给谁、接收用什么类型接收等等。

    • 首先、对于查询多个还是单个,可以使用集合,查询单个、集合中就一条数据,查询多个集合中就多条数据。
    • 对于不知道是那张表、有哪些字段。遍历取值赋值给那个实体类,可以新建一个回调函数来赋值。
    • 回调函数接收的参数就是在通用方法里传来的ResultSet,取出里边的值,给泛型里的实体类赋值,回调函数里的泛型类型就是调用者接收的类型,也就是某个实体类。这样、在通用方法里每循环一次,就调用一次回调函数,而回调函数里知道是那张表,赋值完成后返回,通用函数里使用泛型类型接收后、再添加到list即可。
    • 回调函数要使用面向接口方式、定义接口、针对不同的类、实现接口,传入的泛型类型也是不同的实体类。

    3.3、查询通用方法代码实现

    • 新建一个泛型接口、RowMapper
    public interface RowMapper<T>
    {
        public T getRow(ResultSet resultSet);
    }
    
    • 实现该接口、要遍历那个类、就针对那个类传入对应的泛型类型,比如我这里要遍历Account表、所以:
    public class AccountRowMapperImpl implements RowMapper<Account>
    {
        @Override
        public Account getRow(ResultSet resultSet)
        {
            Account account = null;
            try
            {
                int id = resultSet.getInt(1);
                String pwd = resultSet.getString(2);
                Double balance = resultSet.getDouble(3);
                String name = resultSet.getString(4);
                account = new Account(id,pwd,balance,name);
                return account;
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            return null;
        }
    }
    

    如果是其它表、比如User,那么就再新建一个实现类,泛型参数是User、返回类型也是User。

    • 编写通用方法
    /**
         * 查询通用方法
         * @param sql 查询sql语句
         * @param rowMapper 回调接口、调用者要传入接口实现类
         * @param args 参数列表
         * @return 返回值(集合)
         */
        public List<T> commomSelect(String sql, RowMapper<T> rowMapper, Object... args)
        {
            Connection conn = null;
            PreparedStatement preparedStatement = null;
            ResultSet rs = null;
            List<T> list = new ArrayList<>();
            try
            {
                conn = DBUtils.getConnection();
                preparedStatement = conn.prepareStatement(sql);
                if (args != null)
                {
                    for (int i = 0; i < args.length; i++)
                    {
                        preparedStatement.setObject(i + 1, args[i]);
                    }
                    rs = preparedStatement.executeQuery();
                    while (rs.next())
                    {
                        T t = rowMapper.getRow(rs);//回调 -->调用者提供的一个封装方法ORM
                        list.add(t);
                    }
                }
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            finally
            {
                DBUtils.closeDb(null, preparedStatement, rs);
            }
            return list;
        }
    
    • service层调用者、因为这里是查询单个、所以直接list.get(0)即可。
    public Account select(int id)
        {
            String sql = "select id,pwd,balance,name from Account where id=?";
            List<Account> list = daoUtils.commomSelect(sql, new AccountRowMapperImpl(), id);
            if (!list.isEmpty())
            {
                return list.get(0);
            }
            return null;
        }
    

    概括来讲、增删改比较简单,返回的就只是受影响行数,而查询比较复杂,不知道查询的是那张表、有哪些字段、就更不知道用那个实体类来接收。添加一个回调函数、通过泛型传入相应的实体类,遍历赋值完成后返回给通用方法,通用方法只负责查询和返回,回调函数赋值取值和赋值。

  • 相关阅读:
    phpstorm Failed to create JVM:error code -4
    php内置函数
    多少
    php 正则
    php 数组 array
    位运算题
    c标准库函数 strcat
    strcpy c标准库函数
    编写一个删除c语言程序文件中所有的注释语句
    杂记
  • 原文地址:https://www.cnblogs.com/dcy521/p/14732220.html
Copyright © 2020-2023  润新知