封装数据库增删改查方法

BaseDao

封装好后,我们称这个类为BaseDao.以后任何实现类要操作数据库,都需要继承这个BaseDao.而且,这个BaseDao并不仅限这3个方法,在这个BaseDao类里,其他常用操作应该在这基本的增删改查方法的基础上进行再封装,这样会减少我们很多重复性的操作.


增删改操作的封装

    /**
     *@Author: zsb
     *@Description: 封装的增删改方法
     *@params: String sql, Object...params
     *@Date: 2018/6/1
    */
    public int update(String sql, Object...params){
        int result = 0;
        //try-with-resouece可以在操作后自动关闭资源
        //dbUtils是对JDBC进行简单的封装,通常使用数据库池
        try(Connection conn = dbUtils.getConnection(); PreparedStatement ps = conn.prepareStatement(sql);){
            //向ps预编译的sql语句中添加对应的属性
            setParams(ps,params);
            //执行sql语句,并获得影响的数据库条数
            result = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }

查询方法的封装(反射 + 泛型)

看到过使用 List<Map<Sring, Object>> 的封装方式,感觉并不方便.
这里使用反射+泛型的方式去封装这个查询方法,通过这次封装,也明白了一些ORM框架为什么需要各种映射文件,表列名与实体类属性名应该保证相同.

/**
     *@Author: zsb
     *@Description: 封装的查询方法,使用泛型获取保存所有的查询信息
     *@params:
     *@Date: 2018/6/1
    */
    public <T> List<T> queryForList(Class<T> clazz, String sql, Object... params){

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

        try(Connection conn = dbUtils.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)){
            //占位符赋值
            setParams(ps, params);
            //执行查询
            ResultSet rs = ps.executeQuery();
            //获得对应类的所有属性值
            Field[] fields = clazz.getDeclaredFields();
            while(rs.next()){
                //根据传入类的class生成一个对应的实例,用于保存数据库中对应的每一条数据
                T newObject = clazz.newInstance();
                //结果集每一条数据,都需要找到对应的setter方法遍历赋值一次,这里使用反射来应对不同的返回值情况
                //特别注意,需要表属性名和实体类属性名相同
                for (Field field : fields) {
                    //获取对应变量在数据库中的内容
                    Object columnValue = rs.getObject(field.getName());
                    //获得属性名,并转换为首字母大写,主要是因为set方法后是首字母大写的属性名
                    String UpperFieldName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                    //找到对应的set方法, 这个getType()弄了好一阵,参数需要的是方法参数类型的.class对象
                    Method method = clazz.getMethod("set" + UpperFieldName, field.getType());
                    //执行方法
                    method.invoke(newObject,columnValue);
                }
                list.add(newObject);
            }
        } catch (SQLException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return list;
    }

属性赋值的方法(只是为了协助增删改查方法)

    /**
     *@Author: zsb
     *@Description: 向预编译PrepareStatement的sql语句里添加对应的属性
     *@params:
     *@Date: 2018/6/1
    */
    public void setParams(PreparedStatement ps, Object... params) throws SQLException {
        if(params != null){
            for(int i = 0; i < params.length; i++){
                ps.setObject(i+1,params[i]);
            }
        }
    }

举例

通过使用以上封装的增删改查方法,在处理各种数据库操作时,确实方便很多.在这个基础上,再进行多层的封装,可以减少各种表名,参数的填写,直接可以通过方法名识别出当前需要操作的表格,以及可以去除过多的参数.
以下举例
现在有一个Article类,对应的数据库表名为article,通常,我们需要获取前几个article进行显示(可能是要求是最新的,或者评论数最多的,等等)
因此在以上封装好的查询方法的基础上,我们再封装一个用于获取按照某种排序规则排序后的数据

    /**
     *@Author: zsb
     *@Description: 用于将table表里的数据进行定制排序输出指定内容,这种语句很常用
     *@params:
     *@Date: 2018/6/4
    */
    public <T> List<T> queryRankingByCondition(Class<T> clazz, String table, String condition, String asc, int beginRow, int rowNumber){
        String sql = "SELECT * FROM "+ table + " ORDER BY " + condition +" "+ asc + " LIMIT " + beginRow +","+ + rowNumber;
        return queryForList(clazz, sql,null);
    }

这个方法的参数很多,但是这个方法很常用,有封装的价值.操作不同的表的时候,我们会有不同的实现类,而这个基本的增删改查类(称为baseDao)会是它们的父类,

/**
 * @Author zsb@myblog
 * @Description: 包含各种查询方法, 使用单例模式设计
 * @Modified By:
 * @Date 2018/6/2
 */
public class ArticleDaoImpl extends BaseDao implements ArticleDao {

    private  static ArticleDaoImpl articleDaoImpl = null;

    private ArticleDaoImpl(){ }

    //单例模式,用于获得实例
    public static synchronized ArticleDaoImpl getInstance() {
        if(articleDaoImpl == null){
            articleDaoImpl = new ArticleDaoImpl();
        }
        return articleDaoImpl;
    }

   /**
     *@Author: zsb
     *@Description: 查询最新的文章,最新文章排行
     *@params: articleNum 列表的长度
     *@Date: 2018/6/4
    */
    @Override
    public List<Article> queryUpToDateArticle(int articleNum) {
        return queryRankingByCondition(Article.class,"article","id","DESC",0,articleNum);
    }
}

这样,在实际使用时,就只需要填写需要显示多少个article就可以了.虽然我们的其他实现类继承了BaseDao,但是我并不建议直接使用BaseDao里封装好的方法,因为参数太多,而且在实际使用是,目的不明确,不能通过方法名直接判断具体的相关的操作信息.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值