教學好助手
碼大牛微訊號:ITmadaniu
全面服務、資源分享、學習交流、資訊傳遞
本文主要講解JDBC演變到Mybatis的漸變過程,講解了為什麼要將JDBC封裝成Mybaits這樣一個持久層框架。文末附黑馬程式設計師JDBC學習影片。
1. JDBC實現查詢分析
首先,我們先來看一下,我們最熟悉也是最基礎的透過JDBC查詢資料庫資料,一般需以下的七個步驟:
(1)載入JDBC驅動
(2)建立並獲取資料庫連線
(3)建立 JDBC Statements 物件
(4)設定SQL語句的傳入引數
(5)執行SQL語句並獲得查詢結果
(6)對查詢結果進行轉換處理並將處理結果返回
(7)釋放相關資源
具體實現程式碼如下:
public static List
Connection connection = ;
ResultSet rs = ;
PreparedStatement stmt = ;
List
try {
//載入JDBC驅動
Class。forName(“oracle。jdbc。driver。OracleDriver”)。newInstance;
String url = “jdbc:oracle:thin:@localhost:1521:ORACLEDB”;
String user = “trainer”;
String password = “trainer”;
//獲取資料庫連線
connection = DriverManager。getConnection(url,user,password);
String sql = “select * from userinfo where user_id = ? ”;
//建立Statement物件(每一個Statement為一次資料庫執行請求)
stmt = connection。prepareStatement(sql);
//設定傳入引數
stmt。setString(1, “zhangsan”);
//執行SQL語句
rs = stmt。executeQuery;
//處理查詢結果(將查詢結果轉換成List
ResultSetMetaData rsmd = rs。getMetaData;
int num = rsmd。getColumnCount;
while(rs。next){
Map map = new HashMap;
for(int i = 0;i < num;i++){
String columnName = rsmd。getColumnName(i+1);
map。put(columnName,rs。getString(columnName));
}
resultList。add(map);
}
} catch (Exception e) {
e。printStackTrace;
} finally {
try {
//關閉結果集
if (rs != ) {
rs。close;
rs = ;
}
//關閉執行
if (stmt != ) {
stmt。close;
stmt = ;
}
if (connection != ) {
connection。close;
connection = ;
}
} catch (SQLException e) {
e。printStackTrace;
}
}
return resultList;
}
2. JDBC演變到Mybatis過程
上面我們看到了實現JDBC有七個步驟,哪些步驟是可以進一步封裝的,減少我們開發的程式碼量。
第一步最佳化:連接獲取和釋放
問題描述:
資料庫連線頻繁的開啟和關閉本身就造成了資源的浪費,影響系統的效能。
解決問題:
資料庫連線的獲取和關閉我們可以使用資料庫連線池來解決資源浪費的問題。透過連線池就可以反覆利用已經建立的連線去訪問資料庫了。減少連線的開啟和關閉的時間。
第二步最佳化:SQL統一存取
問題描述:
在使用JDBC進行操作資料庫時,SQL語句基本都散落在各個JAVA類中,這樣有三個不足之處:
1。 可讀性差,不利於維護以及做效能調優;
2。 改動Java程式碼需要重新編譯、打包部署;
3。 不利於取出SQL在資料庫客戶端執行。
解決問題:
可以考慮不把SQL語句寫到Java程式碼中,那麼把SQL語句放到哪裡呢?
首先需要有一個統一存放的地方,可以將這些SQL語句統一集中放到配置檔案或者資料庫裡面(以key-value的格式存放)。然後透過SQL語句的key值去獲取對應的SQL語句。
既然將SQL語句都統一放在配置檔案或者資料庫中,那麼這裡就涉及一個SQL語句的載入問題。
第三步最佳化:傳入引數對映和動態SQL
問題描述:
既然已經把SQL語句統一存放在配置檔案或者資料庫中了,怎麼做到能夠根據前臺傳入引數的不同,動態生成對應的SQL語句呢?
解決問題:
首先解決這個動態問題,按照正常的程式設計師思維是,透過if和else這類的判斷來進行是最直觀的,這個時候可以想到JSTL中的
假設可以,那麼這裡就需要一個專門的SQL解析器來解析這樣的SQL語句,但是,if判斷的變數來自於哪裡呢?傳入的值本身是可變的,那麼我們得為這個值定義一個不變的變數名稱,而且這個變數名稱必須和對應的值要有對應關係,可以透過這個變數名稱找到對應的值,這個時候我們想到了key-value的Map。解析的時候根據變數名的具體值來判斷。
假如前面可以判斷沒有問題,那麼假如判斷的結果是true,那麼就需要輸出的標籤裡面的SQL片段,但是怎麼解決在標籤裡面使用變數名稱的問題呢?這裡需要使用一種有別於SQL的語法來嵌入變數(比如使用#變數名#)。這樣,SQL語句經過解析後就可以動態的生成符合上下文的SQL語句。
如何區分開佔位符變數和非佔位變數?有時候單單使用佔位符是滿足不了的,佔位符只能為查詢條件佔位,SQL語句其他地方使用不了。這裡我們可以使用#變數名#表示佔位符變數,使用$變數名$表示非佔位符變數。
第四步最佳化:結果對映和結果快取
問題描述:
執行SQL語句、獲取執行結果、對執行結果進行轉換處理、釋放相關資源是一整套下來的。假如是執行查詢語句,那麼執行SQL語句後,返回的是一個ResultSet結果集,這個時候我們就需要將ResultSet物件的資料取出來,不然等到釋放資源時就取不到這些結果資訊了。從前面的最佳化來看,以及將獲取連線、設定傳入引數、執行SQL語句、釋放資源這些都封裝起來了,只剩下結果處理這塊還沒有進行封裝,如果能封裝起來,每個資料庫操作都不用自己寫那麼一大堆Java程式碼,直接呼叫一個封裝的方法就可以搞定了。
解決問題:
分析一下,一般對執行結果的有哪些處理,有可能將結果不做任何處理就直接返回,也有可能將結果轉換成一個JavaBean物件返回、一個Map返回、一個List返回等等,結果處理可能是多種多樣的。從這裡看,要告訴SQL處理器兩點:第一,需要返回什麼型別的物件;第二,需要返回的物件的資料結構怎麼跟執行的結果對映,這樣才能將具體的值copy到對應的資料結構上。
接下來,可以進而考慮對SQL執行結果的快取來提升效能。快取資料都是key-value的格式,那麼這個key怎麼來呢?怎麼保證唯一呢?即使同一條SQL語句幾次訪問的過程中由於傳入引數的不同,得到的執行SQL語句也是不同的。那麼快取起來的時候是多對。但是SQL語句和傳入引數兩部分合起來可以作為資料快取的key值。
第五步最佳化:解決重複SQL語句問題
問題描述:
因為將所有SQL語句都放到配置檔案中,這個時候會遇到一個SQL重複的問題,幾個功能的SQL語句其實都差不多,有些可能是SELECT後面那段不同、有些可能是WHERE語句不同。有時候表結構改了,那麼就需要改多個地方,不利於維護。
解決問題:
程式碼程式中出現重複程式碼怎麼辦?將重複的程式碼抽離出來成為獨立的一個類,然後在各個需要使用的地方進行引用。對於SQL重複的問題,可以透過將SQL片段模組化,將重複的SQL片段獨立成一個SQL塊,然後在各個SQL語句引用重複的SQL塊,這樣需要修改時只需要修改一處即可。
3. 最佳化總結
總結一下上面對JDBC的最佳化和封裝:
(1) 使用資料庫連線池對連線進行管理
(2) SQL語句統一存放到配置檔案
(3) SQL語句變數和傳入引數的對映以及動態SQL
(4) 動態SQL語句的處理
(5) 對資料庫操作結果的對映和結果快取
(6) SQL語句的重複
4. 學習影片
黑馬程式設計師 JDBC影片教程(影片+原始碼+PPT)
公眾號後臺回覆:JDBC
即可獲取資源
教學好助手
長按二維碼關注