利用反射实现JDBC的数据库通用查询方法

来源:互联网 发布:淘宝宝贝展示图片大小 编辑:程序博客网 时间:2024/05/16 15:47
/**     * 通用的查询方法     * 这里的SQL语句作为一个变量参数传递进来     * 如果是根据id或者name等模糊查询还需要将具体的参数传递进来     * 但是这里是通用的方法,我们不知道具体传入的是emp还是dept     * 所以直接利用一个对象数组的这样一个参数传递进来     */    //返回一个结果集    public List<E> query(String sql,Object[] parames,Class<?> cla){        //这里还需要一个Class<?>属性来通过方法的名字以及方法的参数属性        //来得到一个方法,这里利用了反射的原理        List<E> list = new ArrayList<E>();        //获取连接        con = JDBCUtil.getConnection();        //预处理        try {            ps = con.prepareStatement(sql);            //由于这里的SQL语句是一个变量            //不知道需要查询哪些变量和哪些字段            //以及对应的字段名是什么            //预处理之后需要设置通过SQL语句传入进来的值            //比如通过id进行查询,and name like%S%等            //那么就需要先将这些问号设置具体的值,而这些值是存放在            //一个对象数组里面的,我们需要通过遍历拿到对应的值,才能进行            //具体的设置            for (int i = 0; i < parames.length; i++) {                ps.setObject(i+1, parames[i]);            }            //做好SQL语句的准备工作之后就是执行SQL语句了            ResultSet rs = ps.executeQuery();            //接下来的工作就是将查询的结果从数据库中返回给用户            //同样利用rs的游标性质,通过while循环取出来            ResultSetMetaData data = rs.getMetaData();            //变化结果集的列数            //通过变化结果集来获取列数            int count = data.getColumnCount();            E o = null;            while(rs.next()){                //通过rs先通过字段类型和字段名称来取出每一行对应的字段的值                //但是现在我们不知道具体是什么类型和字段                //这里我们通过结果集的metadata的属性来获取                //返回的数据类型为结果集变化数据                //然后我们从变化的数据中(metadata)获取字段名称也就是列名                //这里的参数需要传入第几列data.getColumnName(column)                //所以我们还需要拿到变化结果集中由多少列                //遍历data中的列数,依次获取对应的列名                for (int i = 1; i <=count ; i++) {                    /*                     * 从结果集中获取数据                     */                    //之前的做法是通过rs.getstring("addr")                    //但是这里我不知道取出的是什么类型的的字段名称                    //所以直接用getObject来表示                    //然后具体的字段名称直接再用for循环遍历列名的时候                    //用i来取值                    Object val = rs.getObject(i);                    //获取到数据之后就是开始new一个student或者emp将从结果集中取出的一行行的数据                    //封装成一个对象,然后添加到结果集中                    //但是这里我们不能通过new一个对象来获取                    //因为可能有的实体类没有构建构造方法                    //并且构造器需要严格要求字段的顺序保持一致                    //所以这里我们实例化对象的时候采用set+具体的字段名称                    //所以这里我们需要先获取到具体的字段名称,                    String columnName = data.getColumnName(i);                    //获取到实体的具体的字段名称之后就需要构造一个和实体类里面                    //定义的set方法一样的格式来调用set函数                    String relMethodName = "set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1).toLowerCase();                    /*                     *  public void setName(String name) {                                this.name = name;                            }                        到这里我们已经拿到了setName(),下面还需要拿到字段的属性                        同样是利用结果变化数据来拿到columnclassname                     */                    String columnClassName = data.getColumnClassName(i);                    //但是这里我们拿到的只是字段的属性名称,是一个字符串类型的                    //我们需要通过这个名称来转为具体的属性                    //就需要通过forname的反射来实现                    try {                        Class<?> columnType = Class.forName(columnClassName);                        //由于这里返回的class属性太多我们不知道具体是哪个,比如可能有string double int 或者public void 函数等                        //所以这里我们利用Class<?>的泛化来表示 通过属性名称反射的属性                        /**                         * 同时需要注意的是虽然我们已经得到了具体的字段属性                         * 但是Java的数据类型表示方法和数据库的数据类型表示方法不一致                         * 所以我们还需要将Java中数据类型转为数据库的类型                         * 主要需要转换的就是decimal类型                         */                        //所以这里需要一个if判断得到的column type属性是否有decimal属性,有的话                        //就将对应的属性转为int类型                        //同时还需要将里面的值也要强制转为int类型                        if(java.math.BigDecimal.class.equals(columnType)){                            columnType = int.class;                            //这里的val是通过getobject属性获取的,是object类型,所以需要先强制转换为                            //bigdecimal类型,然后转为int类型                            val = ((java.math.BigDecimal)val).intValue();                        }                        try {                            //到这里我们已经拿到了方法名字如:setName                             //以及需要设置的字段的类型 如 string                            //那么就相当于我们可以创建一个public void setName(String name) {}                            //这样的函数方法了                            //要拿到一个实体的set方法那么我们需要先得到这个属性的class属性                            //但是这个实体是一个变化的可能是Emp,或者Dept,                            //所以这里也需要通过一个参数传递进来                            Method method = cla.getMethod(relMethodName, columnType);                            try {                                //现在我们已经得到了方法                                /**                                 *  public void setName(String name) {                                    this.name = name;                                }                                 */                                //然后就是需要找到this  也就是调用方法的执行体                                //而这里的this指的就是当前的对象                                //但是在这个通用的查询方法中我们并不知道                                //传入进来的对象到底是什么,所以我们初始化一个对象                                //利用E o = null,来实例化一个对象泛指所有的对象                                //然后利用方法的invoke属性来执行将取出的val设置给对象O                                method.invoke(o, val);                            } catch (IllegalAccessException e) {                                // TODO Auto-generated catch block                                e.printStackTrace();                            } catch (IllegalArgumentException e) {                                // TODO Auto-generated catch block                                e.printStackTrace();                            } catch (InvocationTargetException e) {                                // TODO Auto-generated catch block                                e.printStackTrace();                            }                        } catch (NoSuchMethodException e) {                            // TODO Auto-generated catch block                            e.printStackTrace();                        } catch (SecurityException e) {                            // TODO Auto-generated catch block                            e.printStackTrace();                        }                    } catch (ClassNotFoundException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }                //封装好对象之后就需要添加到集合中                //遍历一张表就添加一次                //for循环完了就添加一个对象                list.add(o);            }        } catch (SQLException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return list;    }

然后再写一个具体的子类继承上面的通用方法
StuDAO

public class StuDAO extends BaseDAO<Student> {public List<Student> findAll(Object[] parames){        String sql = "select * from student";        //调用父类的方法query        return this.query(sql, parames, Student.class);        //返回当前方法的query方法         //方法中调用方法        //子类中的方法调用父类中的方法        }

这里还需要一个中转作用的StuService,起一个在数据库和用户中间的参数传递的桥梁

public class Stuservice {/**    * findAll()    */   public List<Student> findAll(){       //查询所有的时候不需要参数       //这里定义需要传入的参数为空的集合       Object[] parames ={};       //调用StuDAO的方法findAll       return sd.findAll(parames);   }   }

在测试类中进行测试

public class TestInfo {    private StudentDAO sd = new StudentDAO();    private Stuservice ss  = new Stuservice();    /**     * 查询所有     */    @Test    public void testFindAll(){        //调用StuService的方法findAll,返回一个结果集        List<Student> list = ss.findAll();        for (Student student : list) {            System.out.println(student);        }    }}
阅读全文
0 0
原创粉丝点击