• Java -- JDBC_利用反射及 JDBC 元数据编写通用的查询方法


    1. 先利用 SQL 进行查询,得到结果集;
    2. 利用反射创建实体类的对象:创建对象;
    3. 获取结果集的列的别名;
    4. 再获取结果集的每一列的值, 结合 3 得到一个 Map,键:列的别名,值:列的值;
    5. 再利用反射为 2 的对应的属性赋值:属性即为 Map 的键,值即为 Map 的值。

    使用 JDBC 驱动程序处理元数据

    1. Java 通过JDBC获得连接以后,得到一个Connection 对象,可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表,表中的各个列,数据类型,触发器,存储过程等各方面的信息。根据这些信息,JDBC可以访问一个实现事先并不了解的数据库。
    2. 获取这些信息的方法都是在DatabaseMetaData类的对象上实现的,而DataBaseMetaData对象是在Connection对象上获得的。

    DatabaseMetaData类

    DatabaseMetaData 类中提供了许多方法用于获得数据源的各种信息,通过这些方法可以非常详细的了解数据库的信息:

    1. getURL():返回一个String类对象,代表数据库的URL。
    2. getUserName():返回连接当前数据库管理系统的用户名。
    3. isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。
    4. getDatabaseProductName():返回数据库的产品名称。
    5. getDatabaseProductVersion():返回数据库的版本号。
    6. getDriverName():返回驱动驱动程序的名称。
    7. getDriverVersion():返回驱动程序的版本号。

    ResultSetMetaData 类

    可用于获取关于 ResultSet 对象中列的类型和属性信息的对象:

    1. getColumnName(int column):获取指定列的名称
    2. getColumnCount():返回当前 ResultSet 对象中的列数。
    3. getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
    4. getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
    5. isNullable(int column):指示指定列中的值是否可以为 null。
    6. isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

    举例子来利用反射及 JDBC 元数据编写通用的查询方法:

    首先是反射工具类:

    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    
    /**
     * 反射的 Utils 函数集合
     * 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
     * @author Administrator
     *
     */
    public class ReflectionUtils {
    
        
        /**
         * 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型
         * 如: public EmployeeDao extends BaseDao<Employee, String>
         * @param clazz
         * @param index
         * @return
         */
        @SuppressWarnings("unchecked")
        public static Class getSuperClassGenricType(Class clazz, int index){
            Type genType = clazz.getGenericSuperclass();
            
            if(!(genType instanceof ParameterizedType)){
                return Object.class;
            }
            
            Type [] params = ((ParameterizedType)genType).getActualTypeArguments();
            
            if(index >= params.length || index < 0){
                return Object.class;
            }
            
            if(!(params[index] instanceof Class)){
                return Object.class;
            }
            
            return (Class) params[index];
        }
        
        /**
         * 通过反射, 获得 Class 定义中声明的父类的泛型参数类型
         * 如: public EmployeeDao extends BaseDao<Employee, String>
         * @param <T>
         * @param clazz
         * @return
         */
        @SuppressWarnings("unchecked")
        public static<T> Class<T> getSuperGenericType(Class clazz){
            return getSuperClassGenricType(clazz, 0);
        }
        
        /**
         * 循环向上转型, 获取对象的 DeclaredMethod
         * @param object
         * @param methodName
         * @param parameterTypes
         * @return
         */
        public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes){
            
            for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
                try {
                    //superClass.getMethod(methodName, parameterTypes);
                    return superClass.getDeclaredMethod(methodName, parameterTypes);
                } catch (NoSuchMethodException e) {
                    //Method 不在当前类定义, 继续向上转型
                }
                //..
            }
            
            return null;
        }
        
        /**
         * 使 filed 变为可访问
         * @param field
         */
        public static void makeAccessible(Field field){
            if(!Modifier.isPublic(field.getModifiers())){
                field.setAccessible(true);
            }
        }
        
        /**
         * 循环向上转型, 获取对象的 DeclaredField
         * @param object
         * @param filedName
         * @return
         */
        public static Field getDeclaredField(Object object, String filedName){
            
            for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
                try {
                    return superClass.getDeclaredField(filedName);
                } catch (NoSuchFieldException e) {
                    //Field 不在当前类定义, 继续向上转型
                }
            }
            return null;
        }
        
        /**
         * 直接调用对象方法, 而忽略修饰符(private, protected)
         * @param object
         * @param methodName
         * @param parameterTypes
         * @param parameters
         * @return
         * @throws InvocationTargetException 
         * @throws IllegalArgumentException 
         */
        public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,
                Object [] parameters) throws InvocationTargetException{
            
            Method method = getDeclaredMethod(object, methodName, parameterTypes);
            
            if(method == null){
                throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
            }
            
            method.setAccessible(true);
            
            try {
                return method.invoke(object, parameters);
            } catch(IllegalAccessException e) {
                System.out.println("不可能抛出的异常");
            } 
            
            return null;
        }
        
        /**
         * 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
         * @param object
         * @param fieldName
         * @param value
         */
        public static void setFieldValue(Object object, String fieldName, Object value){
            Field field = getDeclaredField(object, fieldName);
            
            if (field == null)
                throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
            
            makeAccessible(field);
            
            try {
                field.set(object, value);
            } catch (IllegalAccessException e) {
                System.out.println("不可能抛出的异常");
            }
        }
        
        /**
         * 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
         * @param object
         * @param fieldName
         * @return
         */
        public static Object getFieldValue(Object object, String fieldName){
            Field field = getDeclaredField(object, fieldName);
            
            if (field == null)
                throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
            
            makeAccessible(field);
            
            Object result = null;
            
            try {
                result = field.get(object);
            } catch (IllegalAccessException e) {
                System.out.println("不可能抛出的异常");
            }
            
            return result;
        }
    }

    通用的查询方法:

    /**
         * 通用的查询方法:可以根据传入的 SQL、Class 对象返回 SQL 对应的记录的对象
         * @param clazz: 描述对象的类型
         * @param sql: SQL 语句。可能带占位符
         * @param args: 填充占位符的可变参数。
         * @return
         */
        public <T> T get(Class<T> clazz, String sql, Object... args) {
            T entity = null;
    
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                //1. 得到 ResultSet 对象
                connection = JDBCTools.getConnection();
                preparedStatement = connection.prepareStatement(sql);
                for (int i = 0; i < args.length; i++) {
                    preparedStatement.setObject(i + 1, args[i]);
                }
                resultSet = preparedStatement.executeQuery();
    
                //2. 得到 ResultSetMetaData 对象
                ResultSetMetaData rsmd = resultSet.getMetaData();
                
                //3. 创建一个 Map<String, Object> 对象, 键: SQL 查询的列的别名, 
                //值: 列的值
                Map<String, Object> values = new HashMap<>();
                
                //4. 处理结果集. 利用 ResultSetMetaData 填充 3 对应的 Map 对象
                if(resultSet.next()){
                    for(int i = 0; i < rsmd.getColumnCount(); i++){
                        String columnLabel = rsmd.getColumnLabel(i + 1);
                        Object columnValue = resultSet.getObject(i + 1);
                        
                        values.put(columnLabel, columnValue);
                    }
                }
                
                //5. 若 Map 不为空集, 利用反射创建 clazz 对应的对象
                if(values.size() > 0){
                    entity = clazz.newInstance();
                    
                    //5. 遍历 Map 对象, 利用反射为 Class 对象的对应的属性赋值. 
                    for(Map.Entry<String, Object> entry: values.entrySet()){
                        String fieldName = entry.getKey();
                        Object value = entry.getValue();
                        ReflectionUtils.setFieldValue(entity, fieldName, value);
                    }
                }
                
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCTools.releaseDB(resultSet, preparedStatement, connection);
            }
    
            return entity;
        }
  • 相关阅读:
    树莓派成长日记03
    一些特殊文字的过滤Private Use Area:E000F8FF
    MongoDb 相关
    SQL 相关技术点收集贴
    正则表达式提取文本的日期
    MVC 相关技术点收集贴
    使用 json2.js注意点
    C#画图 GDI+
    PHP模拟POST,验证页面的返回状态
    EF-Entity Framework 相关技术点收集贴
  • 原文地址:https://www.cnblogs.com/androidsuperman/p/6953574.html
Copyright © 2020-2023  润新知