JDBC QueryRunner(開源框架)之查詢 詳解

QueryRunner查詢數據庫& QueryRunner如何封裝起來的

一、簡單描述JDBC獲取連接Connection後能做什麼?

首先 查看相關API

(一).使用類和方法

  • QueryRunner(接口的方法如下兩個):
  • update(connection,sql,object…objs) //進行增刪改方法
  • query(connection,sql,ResultSetHandler,object…objs)//查詢方法

    • ResultSetHandler接口
  • 常用實現類:
  • BeanHandler 封裝一個實體對象
  • BeanListHandler 封裝 一組多個實體對象到list
  • ScalarHandler 獲取單個值
  • MapListHanlder 封裝 一組map到list

(二)在詳細的解析了JDBC使用C3P0 或 DBCP獲取了連接Connection 之後

進一步的需要對數據庫進行數據的增刪改查一系列的操作

其中大多數操作(其實可以封裝在DAO裏)不外乎(操作這些共同的方法)

public interface DAO<T> {

 /*  一、批量處理的方法
 *
 * @param connection:  數據庫連接
 * @param sql:  SQL語句
 * @param args:  填充佔位符的Object []類型的可變參數
 */

void batch(Connection connection,String sql,Object[] ...args);

/*   二、返回具體的一個值  如  平均成績  總數
 * 
 * @param connection:  數據庫連接
 * @param sql:  SQL語句
 * @param args:  填充佔位符的可變參數
 */
<E> E getForValue(Connection connection,String sql,Object ...args);

/*   三、返回一個T的一個集合相當於查詢所有記錄
 * 
 * @param connection:  數據庫連接
 * @param sql:  SQL語句
 * @param args:  填充佔位符的可變參數
 */
List<T> getForList(Connection connection,String sql,Object ...args);

/*   四、返回一個T的對象
 * 
 * @param connection:  數據庫連接
 * @param sql:  SQL語句
 * @param args:  填充佔位符的可變參數
 */
T get(Connection connection,String sql,Object ...args) throws SQLException;

/*  五、增刪改操作
 *
 * INSERT UPDATE DELETE
 * @param connection:  數據庫連接
 * @param sql:  SQL語句
 * @param args:  填充佔位符的可變參數
 */
    void update(Connection connection,String sql,Object ...args) throws SQLException;
}

二、此文主要解析使用框架QueryRunner 進行 ★查詢qruery()操作

//正如我們平時使用最流行的 方法進行操作 不多說 上代碼

<1>首先導入jar包(驅動和連接池的不算)

commons-dbutils-1.3.jar

<2>封裝使用C3P0獲取連接和關閉連接 這兩個方法封裝如下:

public class JDBCUtils {

//數據庫連接池值應該被初始化一次放在靜態代碼塊中
private static DataSource datasource=null;
static{
    datasource =new ComboPooledDataSource("helloc3p0");
}
public static  Connection getConnection() throws SQLException{

    return datasource.getConnection();
}

//用完資源後需要關閉

/*釋放資源:
Connection
Statement
ResultSet
1 儘量晚創建早釋放
2 後使用的先關閉*/

public static void release(ResultSet rs,Statement statement,Connection conn){
     if(rs!=null){
            try{
                rs.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

      if(statement!=null){
    try{
        statement.close();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
       if(conn!=null){
        try {
            conn.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
    }
  }
}

<3>步創建QueryRunner 實例對象 調用query()方法

例一、以最複雜查詢所有對象的鍵值對爲例如下:

//分析所有對象的鍵值對 ①鍵值對需要放在Map集合中 多個對象需要放在集合中 所以如下

//不同的查詢方法只是返回結果需要實現的ResultSetHandler接口對象不同

//測試查詢List

@Test
public void testMapList() throws Exception{
    Connection conn =JDBCUtils.getConnection();

    //創建QueryRunner對象
    QueryRunner qr = new QueryRunner();

    //調用方法其query查詢方法

    try{
    //下面需要根據查詢方法創建ResultSetHandler對象
    //將結果集中的每一行數據都封裝到一個Map裏,然後再存放到List

     List<Map<String, Object>> query = qr.query(conn, "select * from 
     表名 where 字段名=?", new MapListHandler(),"女");
    }catch (Exception e){
     System.out(e.getMasage());
    }finally{   //關閉資源

          JDBCUtils.release(conn, null, null);

    }
    //此處作測試直接遍歷Map打印 否則返回
     for (Map<String, Object> map : query) {
         Set<Entry<String, Object>> entrys = map.entrySet();

         Iterator<Entry<String, Object>> iterator = entrys.iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            String key = entry.getKey();
            Object value = entry.getValue();

            System.out.print(key+"\t"+value+" |||| ");
        }
        System.out.println();
    }
}

}

例二、查詢返回某個值如(總數和 或 平均分)

實現如下:

//測試查詢單個值
@Test
public void testScalar() throws Exception{
    Connection conn =JDBCUtils.getConnection();

 //創建QueryRunner對象
 QueryRunner qr = new QueryRunner();

    //調用方法

    Object query = qr.query(conn, "select count(*) from student",  new ScalarHandler());

   //此處測試直接打印(實際應用中返回結果)
    System.out.println(query);

    //關閉連接

    JDBCUtils.release(conn, null, null);
}

三、在沒有使用QueryRunner 框架之前是如何實現的呢?

使用的操作實現類有兩個是prepareStatement和Statement

使用的結果處理有ResultSetMetaData實現類獲取結果對象的對應值

★★那麼prepareStatement和Statement它們有什麼區別呢???

第一:

prepareStatement會先初始化SQL
先把這個SQL提交到數據庫中進行預處理,多次使用可提高效率。

createStatement不會初始化,沒有預處理,沒次都是從0開始執行SQL

第二:

prepareStatement可以替換變量
在SQL語句中可以包含?,可以用ps=conn.prepareStatement("select* from Cust where ID=?");
int sid=1001;
ps.setInt(1, sid);
rs = ps.executeQuery();
可以把?替換成變量。
而Statement只能用
int sid=1001;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from Cust where ID="+sid);
來實現。

第三:

prepareStatement會先初始化SQL,
先把這個SQL提交到數據庫中進行預處理,多次使用可提高效率。
createStatement不會初始化,沒有預處理,沒次都是從0開始執行SQL

例一:

使用方式一:獲取對象爲statement進行查詢單個對象如下

 /**一、使用statement測試查詢單個對象
 * 
 * @throws Exception
 */
@Test
public void testQuery() throws Exception{

    Connection connection =JDBCUtils.getConnection();

    //獲取執行命令對象
    Statement statement = connection.createStatement();

    //執行★

     ResultSet set = statement.executeQuery("select sex,name from 表名");


       while(set.next()){
    //   Object id = set.getObject(1);//得到第一列
         Object name = set.getObject(2);//得到第2列
         Object sex = set.getObject(1);//得到第3列
   //    Object email = set.getObject(4);//得到第4列
   //    Object borndate = set.getObject(5);//得到第5列

         //輸出一個就行測試
         System.out.println(name+"\t"+sex);

     }

    //釋放資源
     JDBCUtils.release(set, statement,connection);
    }
}

例二:

使用方式二:使用PreparedStatement 的對象prepareStatement 改進方式一

查詢所有對象如:

public List<T> query(Class<T> clazz, String sql, Object... objects) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet set = null;
    List<T> list=new ArrayList<>();
    try {
            //1.獲取連接
            connection = JDBCUtils.getConnection();

        //2.獲取PreparedStatement對象prepareStatement

            statement = connection.prepareStatement(sql);

            //爲sql佔位符 賦值
            for (int i = 0; i < objects.length; i++) {
                statement.setObject(i+1, objects[i]);
            }

            //3.執行sql 進行executeQuery()查詢操作並處理結果
             set= statement.executeQuery();

             //創建ResultSetMetaData對象獲取查詢結果的對象對應值
             ResultSetMetaData metaData = set.getMetaData();
             while(set.next()){

             //通過反射創建對象
            T t  = clazz.newInstance();//實體類必須有無參構造

         //遍歷結果集
         for (int i = 0; i < metaData.getColumnCount(); i++) {

         //得到列名
         String name = metaData.getColumnLabel(i+1);
        //得到列對應的值
         Object value = set.getObject(name);

        //通過反射設置屬性
        Field field = clazz.getDeclaredField(name);

        //利用反射對private私有屬性進行暴力破解
        field.setAccessible(true);
        //調用封裝的實體類中的set()方法給屬性賦值         
        field.set(t, value);
                }

       // 將對象放入ArrayList集合中
                 list.add(t);//將t添加到list
             }
       //返回最終結果
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }finally{

        //關閉連接
            JDBCUtils.release(connection, statement, set);
        }
}

四、分析總結

在使用QueryRunner 之前我們的操作對象有兩個

1.prepareStatement和Statement

調用其方法:
           execute()進行查詢 相當於    QueryRunner的query()方法

           executeUpdate()進行增刪改 相當於 QueryRunner的update()方法

2、使用apache下的PropertyUtils將對象賦予查詢的結果
     import org.apache.commons.beanutils.PropertyUtils;
   PropertyUtils.setProperty(t, name, value);

2.處理結果方法有ResultSetMetaData的對象

    調用其方法:
           metaData.getColumnCount()獲取結果集長度

           //獲取其列名或別名
           String name = metaData.getColumnLabel(i+1);

         //獲取其列名或別名對應的值
           Object value = set.getObject(name);
         //將獲取值放入對象中
          PropertyUtils.setProperty(t, name, value);
   相當於相當於 QueryRunner的ResultSetHandler的不同實現對象方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章