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


    /**
         * 通用的查询方法
         * 这里的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);
            }
        }
    
    
    }
    欢迎关注我的公众号:小秋的博客 CSDN博客:https://blog.csdn.net/xiaoqiu_cr github:https://github.com/crr121 联系邮箱:rongchen633@gmail.com 有什么问题可以给我留言噢~
  • 相关阅读:
    python day6
    python day5
    python基础晋级篇
    python基础篇
    初识Python
    if语句
    A22. openstack架构实战-openstack的api
    A21. openstack架构实战-配置三层网络vxlan
    A20. openstack架构实战-虚拟机创建的流程
    A19. openstack架构实战-云主机的冷迁移
  • 原文地址:https://www.cnblogs.com/flyingcr/p/10428309.html
Copyright © 2020-2023  润新知