码迷,mamicode.com
首页 > Web开发 > 详细

ResultSetMetaData和ResultSet

时间:2018-01-15 00:13:09      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:执行sql   select   next   图片   cte   可变参   等等   png   面向对象的思想   

  我现在有一张表t_product;我们查询所有的商品:SELECT * FROM t_product;

技术分享图片

上述所有的数据都可以封装成一个对象,我们称这个查询出来的对象为结果集对象:ResultSet.

对于Java实现查询来说,sql语句是不同的,比如select * from t_product;或者select * from t_product where id=? and name=?;等等。?的个数是不同的,而且不可控制的,结果集合又是不一样的;那么我们如何实现呢?在这里我给出两中实现方案:

方案1:ResultSet单纯实现:

    分析:单个未知的参数,sql语句,结果集对象,参数的个数;首先我定义一个接口,用来专门处理结果集对象;

/**
 * 1 使用泛型声明接口,所有关于查询的类都可以使用该接口
 * 2 传入结果集对象
 * 3 返回结果使用泛型,具体的返回交给子类实现
 * @param <T>
 */
public interface ResultSetHandler<T> {
     T handler(ResultSet rs) throws SQLException;
}

接下来我们就专门的查询写一个方法:传递这三个位置的参数,由于预编译参数个数不确定,这里我们使用可变参数:

 public static <T> T templateDQL(String sql,ResultSetHandler<T> handler,Object...args){
        List<T> list=new ArrayList();
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn=DBUtils.getConn();
            ps=conn.prepareStatement(sql);
            for (int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            /**执行sql语句*/
            rs = ps.executeQuery();
            return  handler.handler(rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

上面的代码先获取连接对象,然后预编译,接着应该是将sql中的?变换成实际值;由于?的个数我们不知道,所以我使用了Object[]数组;使用for循环取出这些?。然后一一赋值;执行完毕sql之后,此时我们需要处理结果集。我们返回这个调用结果,让子类实现;

public class ProductDAOImpl implements IProductDAO {
    private  ResultSetHandler<List<Product>> rsh=new ResultSetHandlerManager();

    public List<Product> getAll() {
        String sql="select * from t_product ";
        return JDBCTemplate.templateDQL(sql, rsh);
    }
    /**
     * 结果集处理器
     */
    class ResultSetHandlerManager implements ResultSetHandler<List<Product>>{
        @Override
        public List<Product> handler(ResultSet rs) throws SQLException {
            List<Product> list=new ArrayList<>();
            while (rs.next()){
                Product product=new Product();
                list.add(product);
                /** rs是结果集对象。*/
                /** 商品的id*/
                Long id = rs.getLong("id");
                /** 商品名称*/
                String name = rs.getString("name");
                /** 商品描述*/
                String descs = rs.getString("descs");
                /** 商品价格*/
                double price = rs.getDouble("price");
                /** 商品的状态*/
                int status = rs.getInt("status");
                /** 库存量*/
                int storeNum = rs.getInt("storeNum");
                product.setId(id);
                product.setPrice(price);
                product.setName(name);
                product.setStatus(status);
                product.setDescs(descs);
                product.setStoreNum(storeNum);
            }
            return list;
        }
    }
}

getAll()方法调用templateDQL(sql, rsh);传入结果集对象,我们在这里定义了rsh.里面封装了一个List,list中保存product对象;具体实现交给ResultSetHandlerManager内部类来实现;对于上述的执行流程我可以画一个时序图来描述;

技术分享图片

至此完成实现第一种的方案;第一种方案处理结果集合我忍为比较麻烦,但是其中的面向对象的思想还是值得学习的,接下来我来说明第二种的实现方案:

方案1:ResultSet和ResultSetMetaData一起来实现:

  ResultSetMetaData是什么东西呢?该对象表示列对象;封装了一个表的列信息,比如id,name.age等等;

public class BaseDao{
    
    public <T> List<T> getObjectForList(Class clz,String sql, Object... args){
        
        List<T> list = null;//要返回的List集合
        Connection con = null;//连接对象
        PreparedStatement ps = null;//预编译对象
        ResultSet resultSet = null;//结果集对象
        T entity = null;//javabean对象(泛型)
        conn=DBUtils.getConn();
    ps=conn.prepareStatement(sql);
    //设置参数
    prepareStateSetArgs(ps,args)
    //执行sql语句,返回结果集合对象
    resultSet = ps.executeQuery();
    // 获取该结果集的列对象
    ResultSetMetaData rsmd = resultSet.getMetaData();
    while (resultSet.next()) {
            //将结果集合对象和列对象转化内成为Map集合
                Map<String, Object> values = putOneResultSetToMap(resultSet, rsmd);
                if (!values.isEmpty()) {
                  //将Map转化为对象,添加到List中;
                    entity = transferMapToBean(clazz,values);//将Map转化为bean的方法请大家自行实现
                    list.add(entity);
                }
            }
    }
    
    private void prepareStateSetArgs(PreparedStatement ps, Object... args) throws SQLException {
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i + 1, args[i]);
        }
    }
    private Map<String, Object> putOneResultSetToMap(ResultSet resultSet, ResultSetMetaData rsmd) throws SQLException {
        Map<String, Object> values = new HashMap<String, Object>();
        
        for (int i = 0; i < rsmd.getColumnCount(); i++) {
            // 循环,获取列及对应的列名
            String columnLabel = rsmd.getColumnLabel(i + 1);
            // 循环,根据列名从ResultSet结果集中获得对应的值
            Object columnValue = resultSet.getObject(columnLabel);
            // 列名为key,列的值为value
            values.put(columnLabel, columnValue);
        }
        return values;
    }
}

第一种方式是怎么处理结果集合呢?简单的说就是通过列的名称获取列的值,如通过 id获取Long id,然后封装到Product对象;现在的做法是通过结果集合获取列对象,通过列对象获取所有的列,然后循环遍历,然后根据列名获取列的值,以列名为key,列值为value.封装到map当中,最后将map转化为我们所需要的对象;其实两种方案最本质的区别是第一种方案直接返回对象,第二种方案是直接返回Map,然后将Map转化为对象

ResultSetMetaData和ResultSet

标签:执行sql   select   next   图片   cte   可变参   等等   png   面向对象的思想   

原文地址:https://www.cnblogs.com/gosaint/p/8284644.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!