1. 程式人生 > >四、利用反射及JDBC元資料編寫通用的查詢方法

四、利用反射及JDBC元資料編寫通用的查詢方法

一、JDBC元資料

1)DatabaseMetaData

/**
     * 瞭解即可:DatabaseMetaData是描述資料庫的元資料物件
     * 可以由Connection得到
     */
@Test
    public void testDatabaseMetaData(){
        Connection connection=null;
        ResultSet resultSet=null;
        try {
            connection=JDBCTools.getConnection();
            DatabaseMetaData data=connection.getMetaData();
            //1.可以得到資料庫本身的一些基本的資訊
            //得到資料庫的版本號
            int version=data.getDatabaseMajorVersion();
            System.out.println(version);
            //2.得到連線資料庫的使用者名稱
            String user=data.getUserName();
            System.out.println(user);
            //3.得到MySQl中有哪些資料庫
            resultSet=data.getCatalogs();
            while(resultSet.next()){
                System.out.println(resultSet.getString(1));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCTools.release(resultSet, null, connection);
        }
    }

2)ResultSetMetaData

/**
     * ResultSetMetaData:描述結果集的元資料
     * 可以得到結果集中的基本資訊:結果集中有哪些列,列名,列的別名等等;
     */
@Test
    public void testResultSetMetaData(){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        try {
            connection=JDBCTools.getConnection();
            String sql="select id,name,email,birth"+
            " from customers";
            preparedStatement=connection.prepareStatement(sql);
            resultSet=preparedStatement.executeQuery();
            ResultSetMetaData rsmd=resultSet.getMetaData();
            //得到列數
            int columnCount=rsmd.getColumnCount();
            System.out.println(columnCount);
            for(int i=0;i<columnCount;i++){
                //得到列名
                String columnName=rsmd.getColumnName(i+1);
                //得到列的別名
                String columnLabel=rsmd.getColumnLabel(i+1);
                System.out.println(columnName+":"+columnLabel);        
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCTools.release(resultSet, preparedStatement, connection);
        }
    }

【溫馨提示】孤立的技術是沒有價值的,結合具體的應用才能彰顯其魅力

我們的查詢操作,對於不同的資料表examstudent和customers,會有不同的程式碼編寫過程,利用反射和JDBC元資料可以編寫通用的方法進行對不同資料表的查詢。

在此之前我們是這樣做的:

查詢customers表中的欄位以及欄位值:

public Customer getCustomer(String sql, Object... args) {
        Customer customer = null;
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCTools.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();
            if (resultSet.next()) {
                // student = new Student(resultSet.getInt(1),
                // resultSet.getInt(2),
                // resultSet.getString(3), resultSet.getString(4),
                // resultSet.getString(5), resultSet.getString(6),
                // resultSet.getInt(7));
                customer = new Customer();
                customer.setId(resultSet.getInt(1));
                customer.setName(resultSet.getString(2));
                customer.setEmail(resultSet.getString(3));
                customer.setBirth(resultSet.getDate(4));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(resultSet, preparedStatement, connection);
        }
        return customer;

    }

查詢examstudent表中的欄位以及欄位值:

public Student getStudent(String sql, Object... args) {
        Student student = null;
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCTools.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();
            if (resultSet.next()) {
                student = new Student(resultSet.getInt(1), resultSet.getInt(2),
                        resultSet.getString(3), resultSet.getString(4),
                        resultSet.getString(5), resultSet.getString(6),
                        resultSet.getInt(7));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(resultSet, preparedStatement, connection);
        }
        return student;

    }

元資料:元資料就是描述資料的資料

可以看到兩個操作有共同的步驟,不同的地方程式碼相似度也很高,於是我們就可以在此基礎上編寫一個通用的方法實現我們查詢資料表的操作。

/**
     * ResultSetMetaData: 
     * 1).是描述ResultSet的元資料物件,即從中可以獲取到 結果集中有多少列,列名是什麼。。。
     * 2).如何使用呢? 1.得到ResultSetMetaData物件: 呼叫ResultSet的getMetaData()方法
     * 2.ResultSetMetaData有哪些好用的方法?
     * 
     * >int getColumnCount():SQL語句中包含哪些列 
     * >String getColumn(int column):獲取指定列的別名,其中索引從1開始
     * 
     */
public <T> T get(Class<T> classz, String sql, Object... args) {
        T entity = null;
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCTools.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();

            ResultSetMetaData rsmd = resultSet.getMetaData();
            Map<String, Object> values = new HashMap<String, Object>();
            if (resultSet.next()) {
                for (int i = 0; i < rsmd.getColumnCount(); i++) {
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    Object columnValue = resultSet.getObject(columnLabel);
                    values.put(columnLabel, columnValue);
                }
            }
            if (values.size() > 0) {
                entity = classz.newInstance();
                for (Map.Entry<String, Object> entry : values.entrySet()) {
                    String fieldName = entry.getKey();
                    Object fieldValue = entry.getValue();
                    ReflectionUtils
                            .setFieldValue(entity, fieldName, fieldValue);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(resultSet, preparedStatement, connection);
        }
        // 返回包含查詢資訊的實體類物件
        return entity;
    }

get方法的編寫實現步驟:

/**
     * 1.先利用SQL進行查詢,得到結果集
     * 2.利用反射建立實體類的物件:建立Student物件
     * 3.獲取結果集的列的別名:idCard、studentName 
     * 4.再獲取結果集的每一列的值,結合3得到一個Map,鍵是列的別名:值;列的值:{flowid:5,type=6,idCard:xxx...} 列的別名和我們實體類的屬性欄位名一致
     * 5.再利用反射為2的對應的屬性賦值   屬性:Map的鍵   屬性值:Map的鍵值
     */

二、BeanUtils包的使用

BeanUtils工具包是由Apache公司所開發,主要是方便程式設計師對Bean類能夠進行簡便的操作。

在使用BeanUtils工具包之前我們需要的Jar包有以下幾種:

(1)   BeanUtils相關包

commons-beanutils-1.8.3.jar

commons-beanutils-1.8.3-javadoc.jar

commons-beanutils-1.8.3-javadoc.jar

commons-beanutils-bean-collections-1.8.3.jar

commons-beanutils-core-1.8.3.jar

(2)   Logic4j相關包 

commons-logging.jar

log4j.jar

      既然要對Bean物件進行操作,那麼就需要一個Bean的測試類,我們以下面為所測試的Bean類

 1 public class Student {
 2 
 3  
 4 
 5        private String name;
 6 
 7        private int age;
 8 
 9        private Date birth;
10 
11  
12 
13  
14 
15        public String getName() {
16 
17               return name;
18 
19        }
20 
21        public void setName(String name) {
22 
23               this.name = name;
24 
25        }
26 
27        public int getAge() {
28 
29               return age;
30 
31        }
32 
33        public void setAge(int age) {
34 
35               this.age = age;
36 
37        }
38 
39        public Date getBirth() {
40 
41               return birth;
42 
43        }
44 
45        public void setBirth(Date birth) {
46 
47               this.birth = birth;
48 
49        }
50 
51  
52 
53 }

1、先賦值Bean物件裡的欄位屬性,然後再取值:

1 @Test
 2 
 3        public void test01() throws Exception{
 4 
 5               //1.載入類
 6  
 7               Class clss = Class.forName("com.L.introspector.Student");
 8 
 9               //2.建立Bean物件
10  
11               Student st = (Student) clss.newInstance();
12 
13               //3.通過BeanUtils給物件屬性賦值
14  
15               BeanUtils.setProperty(st, "name", "L。");
16 
17               //4.輸出物件屬性值
18  
19               String str = BeanUtils.getProperty(st, "name");
20 
21               System.out.println(str);
22 
23 }

BeanUtils的setProperty(object,name,value)方法需要的引數分別是

Object=載入類的物件

Name=類屬性的名稱

Value=所賦的值;

BeanUtils的getProperty(object,name)方法的返回值是String型別,所以可以直接輸出;

因此我們的get方法中的程式碼:

ReflectionUtils.setFieldValue(entity, fieldName, fieldValue);可以更改為

BeanUtils.setProperty(entity, fieldName, fieldValue);