利用元数据编写查询的通用方法

来源:互联网 发布:如何做免费网络推广 编辑:程序博客网 时间:2024/05/17 01:43
一、获取JDBC元数据
     现在在本地数据库中有一个表如下图所示
     现在我们想要查询该表中的某一元组,则查询到的元组可以当作是一个对象,所以有以下Student类对象以及提供数据库相应操作的类JDBCTools:
JDBCTools中有静态的方法release()用来释放数据库连接,以及getConnection()方法用来建立数据库的连接,相应的Student类中除了属性与构造方法之外还有get与set方法以及toString()方法,由于代码有点多,此处就省略了。
public class Student {       public int FlowID;//流水号       public String Type;//考试类型       public String IDcard;//身份证号       public String Examcard;//准考证号码       public String StudentName;//学生姓名       public String Location;//区域       public int Grade;//成绩       public Student(int flowID, String type, String iDcard, String examcard, String studentName, String location,                    int grade) {             super();             FlowID = flowID;             Type = type;             IDcard = iDcard;             Examcard = examcard;             StudentName = studentName;             Location = location;             Grade = grade;       }//这里省略其余的方法。。。}
则想要获取表中的某一元组,原始的方法如下:
public Student getStudent(String sql,Object ... args){//返回学生对象             Student stu = null;             Connection con = null;             PreparedStatement ps = null;             ResultSet rs = null;             try {                    con = jdbcTools.getConnection();                    ps = con.prepareStatement(sql);                    for(int i = 0 ; i < args.length ; ++i){                           ps.setObject(i + 1,args[i]);                    }                    rs = ps.executeQuery();                    if(rs.next()){                           stu = new Student();                                        stu.setFlowID(rs.getInt(1));                                        stu.setType(rs.getString(2));                                        stu.setIDcard(rs.getString(3));                                        stu.setExamcard(rs.getString(4));                                        stu.setStudentName(rs.getString(5));                                        stu.setLocation(rs.getString(6));                                        stu.setGrade(rs.getInt(7));                    }             } catch (Exception e) {                    e.printStackTrace();             } finally{                    jdbcTools.release(rs, con, ps);             }             return stu;       } 
     但是该方法只能用来查询Student类的对象,如果想要查询其他类,则又要变换相应的查询代码,但是变换后的代码与原来的代码相比只是稍有不同罢了,所以我们就想是否可以编写一个通用的查询方法来查询某一个元组呢?答案是可以的。
1、使用JDBC驱动处理元数据
     我们知道,想要编写通用的查询方法,意味着我们要访问一个事先不知道任何其信息的数据库,那我们应该怎么做呢?首先得先获取JDBC的元数据,那么什么是元数据呢?我们之前就知道,当我们在通过JDBC获取对数据库的连接后,会得到一个Connection对象,进而调用该对象的一些方法来对数据库执行操作,所以我们也可以通过该对象来获得相关的数据库的各种信息,这些信息中就有数据库中的各个表,表中的列,数据类型等等一些信息,所以通过它JDBC可以访问一个事先并不了解的数据库。
     所以,如果想要了解一个数据库的版本号,用户名,URL等,可以通过DatabaseMetaData类来获得,那么我们编写通用的查询方法的时候,需要的是有关表中的列的信息,因此,关于这些信息的获取方法,可以通过ResultSetMetaData类来获取,下面介绍一下ResultSetMetaData类。
2、ResultSetMetaData类
     我们都知道,进行数据库的查询操作时,执行executeQuery()方法返回的是一个ResultSet类型的结果集,而我们能对该结果集进行逐行的访问,以及对列进行任意顺序的访问,但是我们并不知到这些列相应的名称是什么,以及ResultSet的对象中的列数等信息,这时候,就需要用getMetaData()方法从结果集ResultSet中获取ResultMetaData对象来获得结果集中每一列的名称,类型以及列数等信息。我们可以用ResultSetMetaData类中的以下方法来获取常用的信息:
     ①getColumnCount()  返回结果集ResultSet中的列数
     ②getColumnName(int index)  返回序号为index的列名,序号从1开始
     ③getColumnLabel(int index) 获取指定列的别名  序号从1开始
     了解了以上的方法后,我们就可以进行编写对未知数据库的通用查询方法了,具体的步骤及其方法看如下代码:
要查询的数据库如下
import java.lang.reflect.Field;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.util.HashMap;import java.util.Map;import org.junit.Test;public class GeneralQuery {@Test       public void test(){             String sql = "SELECT Flow_ID FlowID,ID_card IDcard FROM examstudent WHERE Flow_ID=?";             Student stu = get(Student.class,sql,1001);             System.out.println(stu);       }       public <T> T get(Class<T> clazz,String sql,Object ... args){             T entity = null;             Connection con = null;             PreparedStatement ps = null;             ResultSet rs = null;                          try {                    con = JDBCTools.getConnection();                    ps = con.prepareStatement(sql);                    for(int i = 0; i < args.length; i++){                           ps.setObject(i+1, args[i]);                    }                    //1、得到ResuktSet结果集                    rs = ps.executeQuery();//该结果集能够知道有几行,以及每一行的某一列对应的值                    //2、得到ResultSetMetaData对象                    ResultSetMetaData rsmd =  rs.getMetaData();//该对象可以知道结果集有几列,以及每一列所对应的别名                    //3、创建一个Map<String,Object>对象,用于存列的别名与对应的值                    Map<String,Object> valueMap = new HashMap<>();                    //4、处理结果集ResultSet与ResultSetMetaData来产生键值对entry,将其存入Map集合中                    while(rs.next()){                           for(int i = 0 ; i < rsmd.getColumnCount() ; i++){//遍历每一列,并得到其别名以及相应的值                                 String columnLabel = rsmd.getColumnLabel(i + 1);                                 Object columnValue = rs.getObject(i + 1);                                                                  valueMap.put(columnLabel, columnValue);                           }                           if(valueMap.size() > 0){                           //5、利用反射创建Class类对应的运行时类的对象                                  entity = clazz.newInstance();                           //6、遍历Map集合,利用反射对运行时类的对象对应的属性进行赋值                                 for(Map.Entry<String, Object> entry : valueMap.entrySet()){                                        String fieldname = entry.getKey();                                        Object value = entry.getValue();                                        Field f1 = clazz.getDeclaredField(fieldname);                                        f1.setAccessible(true);                                        f1.set(entity, value);                                 }                           }                    }             } catch (Exception e) {                    e.printStackTrace();             }finally{                    JDBCTools.release(rs, con, ps);             }             return entity;                    }}
在这里附上JDBCTools类的代码:
import java.io.InputStream;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;public class JDBCTools {       public static void update1(String sql , Object ... args){             Connection con = null;             PreparedStatement ps = null;                          try {                    con = getConnection();                    ps = con.prepareStatement(sql);                    for(int i = 0;i<args.length;i++){//索引的下标从1开始  和数组不一样                           ps.setObject(i+1, args[i]);                    }                    ps.executeUpdate();             } catch (Exception e) {                    e.printStackTrace();             }finally{                    release(con, ps);             }       }       public void update(String sql){//实现数据库的更新操作 使用Statement接口             Connection con = null;             Statement state = null;                          try {                    con = getConnection();                                        state = con.createStatement();                                        state.executeUpdate(sql);             } catch (Exception e) {                    e.printStackTrace();             }finally{                    release(con,state);             }                    }       public static Connection getConnection() throws Exception{//连接数据库             String driverClass = null;             String url = null;             String user = null;             String password = null;                          Properties properties = new Properties();                          InputStream in = Review.class.getClassLoader().getResourceAsStream("jdbc.properties");             properties.load(in);                          driverClass = properties.getProperty("driver");             url = properties.getProperty("jdbcurl");             user = properties.getProperty("user");             password = properties.getProperty("password");             Class.forName(driverClass);             return DriverManager.getConnection(url, user, password);       }       public static void release(Connection con , Statement state){//关闭数据库连接             if(state != null){                    try {                           state.close();                    } catch (SQLException e) {                           e.printStackTrace();                    }             }             if(con != null){                    try {                           con.close();                    } catch (SQLException e) {                           e.printStackTrace();                    }             }                    }       public static void release(ResultSet rs , Connection con , Statement state){//关闭数据库连接             if(rs != null)             {                    try {                           rs.close();                    } catch (SQLException e) {                           e.printStackTrace();                    }             }             if(state != null){                    try {                           state.close();                    } catch (SQLException e) {                           e.printStackTrace();                    }             }             if(con != null){                    try {                           con.close();                    } catch (SQLException e) {                           e.printStackTrace();                    }             }       }}