JDBC項目實踐
這幾天學習了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 = value driver = oracle.jdbc.OracleDriver url = jdbc:oracle:thin:@localhost:1521:xe user = fengweijie password= 1070937053 #driver = com.mysql.jdbc.Driver #url = jdbc:mysql:localhost:3306/test?useUni intialSize = 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[]params
if(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