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;
}

Java -- JDBC_利用反射及 JDBC 元数据编写通用的查询方法的更多相关文章

  1. <五>JDBC_利用反射及JDBC元数据编写通用的查询方法

    此类针对javaBean类写了一个通用的查询方法,List<javaBean> 通用查询更新中...:通过学习,深刻体会到学会反射就等于掌握了java基础的半壁江山! 一.使用JDBC驱动 ...

  2. JDBC学习笔记(5)——利用反射及JDBC元数据编写通用的查询方法

    JDBC元数据 1)DatabaseMetaData /** * 了解即可:DatabaseMetaData是描述数据库的元数据对象 * 可以由Connection得到 */ 具体的应用代码: @Te ...

  3. 【转】JDBC学习笔记(5)——利用反射及JDBC元数据编写通用的查询方法

    转自:http://www.cnblogs.com/ysw-go/ JDBC元数据 1)DatabaseMetaData /** * 了解即可:DatabaseMetaData是描述数据库的元数据对象 ...

  4. MYSQL 之 JDBC(六): 增删改查(四)利用反射及JDBC元数据编写通用的查询

    1.先利用SQL进行查询,得到结果集2.利用反射创建实体类的对象:创建Student对象3.获取结果集的列的别名:idCard.studentName4.再获取结果集的每一列的值,结合3得到一个Map ...

  5. 利用反射及jdbc元数据实现通用的查询方法

    ---------------------------------------------------------------------------------------------------- ...

  6. JDBC--利用反射及JDBC元数据编写通用的查询方法

    1.JDBC元数据(ResuleSetMetaData):描述ResultSet的元数据对象,可以从中获取到结果集中的列数和列名等: --使用ResultSet类的getMetaData()方法获得R ...

  7. java攻城狮之路--复习JDBC(利用BeanUtils、JDBC元数据编写通用的查询方法;元数据;Blob;事务;批量处理)

    1.利用BeanUtils的前提得要加入以下两个jar包: commons-beanutils-1.8.0.jar commons-logging-1.1.1.jar package com.shel ...

  8. 利用反射及JDBC元数据编写通用查询方法

    元数据:描述数据的数据,ResultSetMetaData是描述ResultSet的元数据对象,从它可以得到数据集有多少了,每一列的列名... ResultSetMetaData可以通过ResultS ...

  9. JDBC课程5--利用反射及JDBC元数据(ResultSetMetaData)编写通用的查询方法

    /**-利用反射及JDBC元数据编写通用的查询方法 * 1.先利用SQl语句进行查询,得到结果集--> * 2.查找到结果集的别名:id--> * 3.利用反射创建实体类的对象,创建aut ...

随机推荐

  1. Express中间件,看这篇文章就够了(#^.^#)

    底层:http模块 express目前是最流行的基于Node.js的web开发框架,express框架建立在内置的http模块上, var http = require('http') var app ...

  2. <编写有效用例>读书笔记3

    <编写有效用例>读书笔记3 第三部分主要内容是对忙于编写用例的人的提示第20章:对每个用例的提示1.每个用例都是一篇散文:这个提示提醒我们将注意力集中与文字而不是图画上,同时帮助了解将要遇 ...

  3. idea 设置注释

    idea和eclipse的注释还是有一些差别的. idea: 类头注释:打开file->setting->Editor->Filr and Code Templates->In ...

  4. leetcode: 638.大礼包

    题目描述: https://leetcode-cn.com/problems/shopping-offers/ 解题思路: 这类求最大最小的问题首先想到的就是用DP求解. 这题还用到了递归,首先计算单 ...

  5. MYSQL InnoDB Cluster

    https://dev.mysql.com/doc/refman/5.7/en/group-replication.html GroupReplication的原理 https://dev.mysql ...

  6. java mail session使用Properties的clone方法

    /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreem ...

  7. 如何批量删除Docker中已经停止的容器

    如何批量删除Docker中已经停止的容器   方法一: #显示所有的容器,过滤出Exited状态的容器,取出这些容器的ID, sudo docker ps -a|grep Exited|awk '{p ...

  8. C++拷贝构造函数的调用时机

    一.拷贝构造函数调用的时机 ​ 当以拷贝的方式初始化对象时会调用拷贝构造函数,这里需要注意两个关键点,分别是以拷贝的方式和初始化对象 1. 初始化对象 初始化对象是指,为对象分配内存后第一次向内存中填 ...

  9. Linux基础学习(3)--初学注意

    第三章——初学注意 一.学习Linux的注意事项 1.Linux严格区分大小写 2.Linux中所有内容以文件形式保存,包括硬件: (1)硬盘文件是/dev/sd[a-p] (2)光盘文件是/dev/ ...

  10. loadrunner 基础-学习笔记一

    由于公司要使用loadrunner暂停学习jmeter 1 loadrunner组件: virtual user generator:录制最终用户业务流程并创建自动化性能测试脚本,vuser脚本 co ...