標籤:
這幾天學習了JDBC的介面,從簡單的串連,到不斷地對JDBC的代碼進行最佳化,最後到實體類,DAO類的設計,現在對這幾天所學做一個總結:
首先是軟體的系統組成:
資料庫中有很多的表:Customer,Department,Order,Account等等,為了訪問每個表,在java中建立相關的DAO,這些DAO構成資料訪問層。java通過調用DAO,達到訪問資料庫的目的
下面是工程的建立步驟:
1:匯入工具包以及設定檔
1.1:匯入訪問JDBC的驅動包:commons-dbcp2-2.1.1.jar,commons-logging-1.2.jar,commons-pool2-2.42.jar,ojdbc6.jar並對不同的包buildpath;
1.2: 建立Utils包,匯入工具類DBUtils.java和設定檔db.properties,這兩個工具類是JDBC的核心包,裡面有串連資料庫,中斷連線的方法
DBUTils.java的原始碼:
package utils;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;import org.apache.commons.dbcp2.BasicDataSource;public class DBUtils { private static String driver = null; private static String url = null; private static String user = null; private static String password = null; private static BasicDataSource ds = null; //靜態塊 static{ Properties props = new Properties(); try { //路徑使用包路徑 String path = "utils/db.properties"; props.load( DBUtils.class.getClassLoader() .getResourceAsStream(path)); driver = props.getProperty("driver"); url = props.getProperty("url"); user = props.getProperty("user"); password = props.getProperty("password"); //ds中已經有了幾個建立好的串連 ds = new BasicDataSource();//建立串連池 ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(user); ds.setPassword(password); ds.setInitialSize( Integer.parseInt(props.getProperty("intialSize"))); } catch (Exception e) { e.printStackTrace(); } } /*建立串連*/ public static Connection getConnection() throws ClassNotFoundException, SQLException{ Connection conn = null; if(ds!=null){ conn = ds.getConnection(); } return conn; } /*關閉串連*/ public static void closeConnection(Connection conn) throws SQLException{ if(conn!=null) conn.close(); } }View Code
讀取的設定檔db.properties,裡面放了Oracle的驅動,url,使用者user密碼 格式是key = value
db.properties的原始碼:
#key = valuedriver = oracle.jdbc.OracleDriverurl = jdbc:oracle:thin:@localhost:1521:xeuser = fengweijiepassword= 1070937053#driver = com.mysql.jdbc.Driver#url = jdbc:mysql:localhost:3306/test?useUniintialSize = 10
View Code
完成之後項目:
2:建立實體包entity:裡面存放的是資料庫裡面的表,例如部門表Dept,員工表Emp,根據表的資料類型建立Dept.java和Emp.java,並在Dept.java和Emp.java中添加get(),set()方法,以及tostring()方法;完成之後項目;
3:建立iDAO包:裡面存放的是訪問資料庫的介面,以員工表和部門表為例,對應的是IEmp.java,Idept.java
4:建立DAO包:裡面是實現IDAO的資料訪問層,對應EmpDAO.java,Dept.java,用來實現訪問資料庫中對用的表
由於2,3,4步驟是體力活,所以一步到位,項目:
下面概述一下項目架構中的技巧:
由於在DAO中,每一個方法都需要獲得串連資料庫,以find函數為例,實現部門表的尋找,每次都需要進行串連,查詢,關閉,代碼如下:
public void find(){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DBUtils.getConnection(); //事務開始 conn.setAutoCommit(false); //商務邏輯 conn.commit(); } catch (Exception e) { try { conn.rollback(); } catch (SQLException sqkex) { // TODO Auto-generated catch block sqkex.printStackTrace(); } e.printStackTrace(); }finally { try { conn.setAutoCommit(true); if(conn !=null) conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
不同函數之間,例如按照部門編號尋找,按照部門所處位置尋找,等等,只是代碼中的商務邏輯不同,其他的部分一致,而除了部門表以外,其他比如員工表也需要進行查詢,也是商務邏輯不同,為瞭解決這個問題,需要寫一個總的find方法,放在BaseDAO中
BaseDAO的原始碼:
package DAO;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;import utils.DBUtils;public abstract class BaseDAO<T> { /* * 所有find方法的三大差別 * 1:SQL語句不通 * 2:?參數有幾個不確定,類型不確定 * 解決方案:類型不確定用:用object接住 * 個數不確定用數組解決 * Object[] params能接住所有的 * 3:傳回值對象不確定,解決 泛型類 */ protected List<T> find(String sql,Object[] params)throws Exception{ List<T> l = new ArrayList<T>(); Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DBUtils.getConnection(); pstmt = conn.prepareStatement(sql); //問題1:不知道set什麼,set幾次 //有Object[]params if(params!=null) for (int i = 0; i < params.length; i++) { pstmt.setObject(i+1, params[i]); } rs = pstmt.executeQuery(); while(rs.next()){ l.add(toEntity(rs)); } return l; } catch (Exception ex) { throw ex; }finally { if(rs!= null) rs.close(); if(pstmt != null) pstmt.close(); DBUtils.closeConnection(conn); } } /* * 因為while中的對象屬性差異無法統一 * 完全交給子類自行完成 * */ public abstract T toEntity(ResultSet rs) throws Exception; }View Code
在BaseDAO 中,面臨的問題有三:
1:SQL語句的不同,
2:SQL語句中的參數類型不能確定
3:返回的對象不能確定
解決的方法分別是:
1:SQL語句不同,定義String sql變數
2:SQL語句中的參數類型不確定,使用Object[]params接住所有的參數
3:傳回值對象不確定,使用泛型,當其他的DAO繼承BaseDAOI時候,將T改寫為對應的類型即可;
因此find的生命定義為:protected List<T> find(String sql,Object[] params)throws Exception{}
find 函數中的經典代碼:
1:在商務邏輯中填入參數:
//問題1:不知道set什麼,set幾次//有Object[]paramsif(params!=null) for (int i = 0; i < params.length; i++) { pstmt.setObject(i+1, params[i]); }
2:返回結果:
while(rs.next()){ l.add(toEntity(rs));}
因為在while中的資料類型差異太大,無法統一,完全交給子類處理,定義抽象方法:
public abstract T toEntity(ResultSet rs) throws Exception;
項目原始碼:http://download.csdn.net/detail/generoius/9378231
JDBC項目實踐