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的不同實現對象方法