zoukankan      html  css  js  c++  java
  • JDBC工具类——JdbcUtils(3)

    JDBC工具类——JdbcUtils(3)

    前言

    本系列文章介绍JDBC工具类——JdbcUtils的封装,部分实现参考了Spring框架的JdbcTemplate

    完整项目地址:https://github.com/byx2000/JdbcUtils

    回顾

    在上一篇文章中,我们抽象出了一个ResultSetMapper<T>接口,用于封装用户对结果集的处理。

    假如用户想把结果集转换成一个User列表,则需要写如下实现类:

    public class UserListResultSetMapper implements ResultSetMapper<List<User>>
    {
        @Override
        public List<User> map(ResultSet rs) throws Exception
        {
            List<User> users = new ArrayList<>();
            while (rs.next())
            {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                users.add(user);
            }
            return users;
        }
    }
    

    假如用户想把结果集转换成一个Book列表,则需要写如下实现类:

    public class BookListResultSetMapper implements ResultSetMapper<List<Book>>
    {
        @Override
        public List<User> map(ResultSet rs) throws Exception
        {
            List<Book> books = new ArrayList<>();
            while (rs.next())
            {
                Book book = new Book();
                book.setId(rs.getInt("id"));
                book.setName(rs.getString("name"));
                book.setAuthor(rs.getString("author"));
                books.add(book);
            }
            return books;
        }
    }
    

    仔细观察两个实现类的代码,可以发现存在着如下重复的结构:

    ...
    while (rs.next())
    {
        ...
    }
    

    这提醒我们,还可以进一步抽象。

    抽象RowMapper<T>

    我们知道,数据库的查询结果是一张表,而一张表中每行的格式都是相同的。所以,用户真正关心的问题不是如何处理整个结果集,而是如何处理结果集中的每一行

    于是,我们可以抽象出一个RowMapper<T>接口,用来封装对数据行的处理:

    /**
     * 行转换器接口
     * @param <T> 转换类型
     */
    public interface RowMapper<T>
    {
        T map(ResultSet rs) throws Exception;
    }
    

    仔细一看,RowMapper<T>接口和ResultSetMapper<T>接口非常像,甚至它们里面的map方法签名都是一样的。但是这两个接口有本质上的不同:ResultSetMapper<T>接口封装了对整个结果集的处理,而RowMapper<T>接口封装了对结果集中一行数据的处理。也就是说,在RowMapper<T>接口的实现类中,只能调用ResultSet.getXXX方法获取列中的值,而不会调用ResultSet.next方法。

    下面是把数据行转换成User类的RowMapper实现类:

    public class UserRowMapper implements RowMapper<User>
    {
        @Override
        public User map(ResultSet rs) throws Exception
        {
            User user = new User();
            user.setId(rs.getInt("id"));
            user.setUsername(rs.getString("username"));
            user.setPassword(rs.getString("password"));
            return user;
        }
    }
    

    下面是把数据行转换成Book类的RowMapper实现类:

    public class BookRowMapper implements RowMapper<Book>
    {
        @Override
        public User map(ResultSet rs) throws Exception
        {
            Book book = new Book();
            book.setId(rs.getInt("id"));
            book.setName(rs.getString("name"));
            book.setAuthor(rs.getString("author"));
            return book;
        }
    }
    

    实现ListResultSetMapper<T>

    在大部分时候,都需要将整个结果集转换成一个列表,所以我们实现一个ListResultSetMapper<T>类,并配合RowMapper<T>完成这项工作:

    public class ListResultSetMapper<T> implements ResultSetMapper<List<T>>
    {
        private final RowMapper<T> rowMapper;
    
        public ListResultSetMapper(RowMapper<T> rowMapper)
        {
            this.rowMapper = rowMapper;
        }
    
        @Override
        public List<T> map(ResultSet rs) throws Exception
        {
            List<T> result = new ArrayList<>();
            while (rs.next())
            {
                result.add(rowMapper.map(rs));
            }
            return result;
        }
    }
    

    有了ListResultSetMapper<T>,再加上上面的两个RowMapper<T>实现类,查询操作就可以简化成如下形式:

    // 查询所有id大于5的用户
    List<User> users = JdbcUtils.query("SELECT * FROM users WHERE id > ?",
                    new ListResultSetMapper<>(new UserRowMapper()),
                    5);
    
    // 查询所有图书
    List<Book> books = JdbcUtils.query("SELECT * FROM books",
                    new ListResultSetMapper<>(new BookRowMapper()));
    

    当然,UserRowMapperBookRowMapper这两个类也可以写成匿名内部类或者lambda表达式的形式。

    总结

    到目前为止,我们抽象出了ResultSetMapper<T>RowMapper<T>这两个重要概念,对结果集的处理进行了更加细致的责任划分。在下一篇文章中,将介绍几个通用的RowMapperResultSetMapper的实现。

  • 相关阅读:
    QT信号槽传递自定义结构体
    Qt5MVC模式(一)
    深层次理解MVC
    代码重构与单元测试——测试项目(二)
    代码重构与单元测试(一)
    在Visual Studio 中使用git——同步到远程服务器-下(十二)
    在Visual Studio 中使用git——同步到远程服务器-上(十一)
    在Visual Studio 中使用git——标记(Tag)管理(十)
    在Visual Studio 中使用git——分支管理-下(九)
    在Visual Studio 中使用git——分支管理-上(八)
  • 原文地址:https://www.cnblogs.com/baiyuxuan/p/14329608.html
Copyright © 2011-2022 走看看