Java JDBC入门之七 : 利用反射及 JDBC 元数据编写通用的查询方法

Java JDBC入门之六 : 利用反射及 JDBC 元数据编写通用的查询方法

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):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

ResultSetMetaData 的主要使用

1).what:是描述 ResultSet 的元数据对象,即从中可以获取到结果集中有多少列,列名是什么。。。

2). how:

①. 得到ResultSetMetadata 对象 :调用 ResultSet 的 getMetaData()

②. ResultSetMetadata 有哪些好用的方法:

> int getColumnCount(): SQL 语句中包含哪些列

> String getColumnLabel(int column): 获取指定的列的别名,其中的索引从1开始。

单行数据查询底层通用方法,其他底层方法可看我的其他博客

/**
 * 通用单行查询方法
 * @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 columnValues = resultSet.getObject(columnLabel);
					
					values.put(columnLabel, columnValues);
				}
			}
			//5. 若 Map 不为 空集 ,利用反射创建 clazz 对应的对象
			if (values.size() > 0) {
				entity = clazz.newInstance();
				//6. 遍历 Map 对象,利用反射为Class 对象的对应属性赋值。
				for (Map.Entry<String, Object> entry : values.entrySet()) {
					String fieldName = entry.getKey();
					Object fieldValues = entry.getValue();
					ReflectionUtils.setFieldValue(entity, fieldName, fieldValues);
				}
			}
			
		}
		catch(Exception e) {
			
		}finally {
			JDBCTools.releaseDB(resultSet, preparedStatement, connection);
		}
		return entity;
	}

附:反射操作工具类

/**
 * 反射的 Utils 函数集合
 * 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
 * @author 
 *
 */
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;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值