#### 10.1 DAO概念> DAO:Data Access Object,數據訪問對象。 > > Java是面向對象語言,數據在Java中通常以對象的形式存在。一張表對應一個實體類,一張表的操作對應一個DAO對象!
? ? >
> 在Java操作數據庫時,我們會將對同一張表的增刪改查操作統一維護起來,維護的這個類就是DAO層。 >
????在開發中,我們會為數據庫中的每一張表創建一個對應的DAO 類,這個 DAO 類專門負責處理與該表相關的所有數據庫操作。
- 如果數據庫中有一張
user
表(存儲用戶信息),我們就會創建一個UserDAO
類 - 這個
UserDAO
類中只會包含對user
表的操作方法:- 添加用戶(對應
user
表的 INSERT 操作) - 查詢用戶(對應
user
表的 SELECT 操作) - 更新用戶(對應
user
表的 UPDATE 操作) - 刪除用戶(對應
user
表的 DELETE 操作)
- 添加用戶(對應
DAO層只關注對數據庫的操作,供業務層Service調用,將職責劃分清楚!# 10.1 BaseDAO概念> 基本上每一個數據表都應該有一個對應的DAO接口及其實現類,發現對所有表的操作(增、刪、改、查)代碼重復度很高,所以可以抽取公共代碼,給這些DAO的實現類可以抽取一個公共的父類,復用增刪改查的基本操作,我們稱為BaseDAO。/*** 通用的查詢:多行多列、單行多列、單行單列* 多行多列:List<Employee>* 單行多列:Employee* 單行單列:封裝的是一個結果。Double、Integer、。。。。。* 封裝過程:* 1、返回的類型:泛型:類型不確定,調用者知道,調用時,將此次查詢的結果類型告知BaseDAO就可以了。* 2、返回的結果:通用,List 可以存儲多個結果,也可以存儲一個結果 get(0)* 3、結果的封裝:反射,要求調用者告知BaseDAO要封裝對象的類對象。 Class*/
?if(params!=null && params.length > 0){
for (int i = 0; i < params.length; i++) {
//占位符是從1開始的。參數的數組是從0開始的
preparedStatement.setObject(i+1,params[i] );
}
}
? ? /*
通用的查詢多個Javabean對象的方法,例如:多個員工對象,多個部門對象等
這里的clazz接收的是T類型的Class對象,
如果查詢員工信息,clazz代表Employee.class,
如果查詢部門信息,clazz代表Department.class,
返回List<T> list
*/
? ? ? ?/*
獲取結果集的元數據對象。
元數據對象中有該結果集一共有幾列、列名稱是什么等信息
*/
? ResultSetMetaData metaData = res.getMetaData();
int columnCount = metaData.getColumnCount();//獲取結果集列數
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;/*** 將共性的數據庫的操作代碼封裝在BaseDAO里。*/
public class BaseDAO {/*** 通用的增刪改的方法。* @param sql 調用者要執行的SQL語句* @param params SQL語句中的占位符要賦值的參數* @return 受影響的行數*/public int executeUpdate(String sql,Object... params)throws Exception{//1.通過JDBCUtilV2獲取數據庫連接Connection connection = JDBCUtilV2.getConnection();//2.預編譯SQL語句PreparedStatement preparedStatement = connection.prepareStatement(sql);//4.為占位符賦值,執行SQL,接受返回結果if(params!=null && params.length > 0){for (int i = 0; i < params.length; i++) {//占位符是從1開始的。參數的數組是從0開始的preparedStatement.setObject(i+1,params[i] );}}int row = preparedStatement.executeUpdate();//5.釋放資源preparedStatement.close();if(connection.getAutoCommit()){JDBCUtilV2.release();}//6.返回結果return row;}/*** 通用的查詢:多行多列、單行多列、單行單列* 多行多列:List<Employee>* 單行多列:Employee* 單行單列:封裝的是一個結果。Double、Integer、。。。。。* 封裝過程:* 1、返回的類型:泛型:類型不確定,調用者知道,調用時,將此次查詢的結果類型告知BaseDAO就可以了。* 2、返回的結果:通用,List 可以存儲多個結果,也可以存儲一個結果 get(0)* 3、結果的封裝:反射,要求調用者告知BaseDAO要封裝對象的類對象。 Class*/public <T> List<T> executeQuery(Class<T> clazz,String sql,Object... params)throws Exception{//獲取連接Connection connection = JDBCUtilV2.getConnection();//預編譯SQL語句PreparedStatement preparedStatement = connection.prepareStatement(sql);//設置占位符的值if(params!=null && params.length > 0){for (int i = 0; i < params.length; i++) {preparedStatement.setObject(i+1, params[i]);}}//執行SQL,并接受返回的結果集ResultSet resultSet = preparedStatement.executeQuery();//獲取結果集中的元數據對象//包含了:列的數量、每個列的名稱ResultSetMetaData metaData = resultSet.getMetaData();int columnCount = metaData.getColumnCount();List<T> list = new ArrayList<>();//處理結果while(resultSet.next()){//循環一次,代表有一行數據,通過反射創建一個對象T t = clazz.newInstance();//循環遍歷當前行的列,循環幾次,看有多少列for (int i = 1; i <=columnCount ;i++){//通過下表獲取列的值Object value = resultSet.getObject(i);//獲取到的列的value值,這個值就是t這個對象中的某一個屬性//獲取當前拿到的列的名字 = 對象的屬性名String fieldName = metaData.getColumnLabel(i);//通過類對象和fieldName獲取要封裝的對象的屬性Field field = clazz.getDeclaredField(fieldName);//突破封裝的privatefield.setAccessible(true);field.set(t,value);}list.add(t);}resultSet.close();preparedStatement.close();if(connection.getAutoCommit()){JDBCUtilV2.release();}return list;}/*** 通用查詢:在上面查詢的集合結果中獲取第一個結果。 簡化了獲取單行單列的獲取、單行多列的獲取*/public <T> T executeQueryBean(Class<T> clazz,String sql,Object... params)throws Exception{List<T> list = this.executeQuery(clazz, sql, params);if(list ==null || list.size() == 0){return null;}return list.get(0);}
}