目前Mybatis是最主流的,為了學好Mybatis,我們先要搞明白JDBC。JDBC(Java DataBase Connectivity)就是Java數據庫連接,說白了就是用Java語言來操作數據庫。原來我們操作數據庫是在控制檯使用SQL語句來操作數據庫,JDBC是用Java語言向數據庫發送SQL語句。
1,JDBC是一套協議,是JAVA開發人員和數據庫廠商達成的協議,也就是由Sun定義一組接口,由數據庫廠商來實現,並規定了JAVA開發人員訪問數據庫所使用的方法的調用規範。
2,JDBC的實現是由數據庫廠商提供,以驅動程序形式提供。
3,JDBC在使用前要先加載驅動。
JDBC對於使用者要有一致性,對不同的數據庫其使用方法都是相同的。
驅動開發必須要實現Driver接口。
數據庫驅動的實現方式 :
JDBC-ODBC橋接式
JDBC網絡驅動,這種方式是通過中間服務器的協議轉換來實現的
JDBC+本地驅動,這種方式的安全性比較差。
JDBC驅動,由數據庫廠商實現。
2 JDBC的API及應用步驟
1、java.sql包和javax.sql包
Driver接口(驅動),在加載某一 Driver 類時,它應該創建自己的實例並向 DriverManager 註冊該實例。這意味著用戶可以通過調用以下程序加載和註冊一個驅動程序
Class.forName("oracle.jdbc.driver.OracleDriver")
DriverManager類(驅動管理器),它可以創建連接,它本身就是一個創建Connection的工廠(Factory)。
Connection接口,會根據不同的驅動產生不同的連接
Statement接口,發送sql語句
ResultSet接口(結果集),是用來接收select語句返回的查詢結果的。其實質類似於集合。
2、JDBC應用步驟
執行一次JDBC連接,分六個步驟進行:
1. 導入包
在程序中包含數據庫編程所需的JDBC類。大多數情況下,使用 import java.sql.* 就足夠了
2. 註冊JDBC驅動程序
需要初始化驅動程序,這樣就可以打開與數據庫的通信。
3. 打開一個連接
使用DriverManager.getConnection()方法來創建一個Connection對象,它代表一個數據庫的物理連接。
4. 執行一個查詢
需要使用一個類型為Statement或PreparedStatement的對象(兩者區別看後文),並提交一個SQL語句到數據庫執行查詢。
5. 從結果集中提取數據
這一步中演示如何從數據庫中獲取查詢結果的數據。使用ResultSet.getXXX()方法來檢索的數據結果
6. 清理環境資源
在使用JDBC與數據交互操作數據庫中的數據後,應該明確地關閉所有的數據庫資源以減少資源的浪費。本文使用了try with resources方式關閉資源,這是JDK7的語法糖,讀者可自行搜索。
注意點:
數據庫資源是非常昂貴的,用完了應該儘快關閉它。Connection, Statement, ResultSet等JDBC對象都有close方法,調用它就好了。
在代碼中必須顯式關閉掉ResultSet,Statement,Connection,如果你用的是連接池的話,連接用完後會放回池裡,但是沒有關閉的ResultSet和Statement就會造成資源洩漏了。
在finally塊中關閉資源,保證即便出了異常也能正常關閉。
大量相似的查詢應當使用批處理完成。
儘量使用PreparedStatement而不是Statement,以避免SQL注入,同時還能通過預編譯和緩存機制提升執行的效率。
如果你要將大量數據讀入到ResultSet中,應該合理的設置fetchSize以便提升性能。
你用的數據庫可能沒有支持所有的隔離級別,用之前先仔細確認下。
數據庫隔離級別越高性能越差,確保你的數據庫連接設置的隔離級別是最優的。
如果你需要長時間對ResultSet進行操作的話,儘量使用離線的RowSet。
4 FAQ
1、JDBC是如何實現Java程序和JDBC驅動的松耦合?
JDBC API使用Java的反射機制來實現Java程序和JDBC驅動的松耦合。看一下上文的JDBC示例,你會發現所有操作都是通過JDBC接口完成的,而驅動只有在通過Class.forName反射機制來加載的時候才會出現。
這是Java核心庫裡反射機制的最佳實踐之一,它使得應用程序和驅動程序之間進行了隔離,讓遷移數據庫的工作變得更簡單。
2、Statement和PreparedStatement區別
關係:PreparedStatement繼承自Statement,兩者都是接口
區別:PreparedStatement可以使用佔位符,而且是預編譯的,批處理比Statement效率高
3、預編譯
創建時的區別:
執行時的區別:
由上可以看出,PreparedStatement有預編譯的過程,已經綁定sql,之後無論執行多少次,都不會再去進行編譯,而Statement 不同,如果執行多次,則相應的就要編譯多少次sql,所以從這點看,PreparedStatement的效率會比Statement要高一些。PreparedStatement是預編譯的,所以可以有效的防止SQL注入等問題
4、佔位符
PrepareStatement可以替換變量在SQL語句中可以包含?,可以用?替換成變量。
而Statement只能用字符串拼接。
int sid = 1001;Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery("select * from Employees where id=" + sid);
5、JDBC的ResultSet
在查詢數據庫後會返回一個ResultSet,它就像是查詢結果集的一張數據表。
ResultSet對象維護了一個遊標,指向當前的數據行。開始的時候這個遊標指向的是第一行。如果調用了ResultSet的next()方法遊標會下移一行,如果沒有更多的數據了,next()方法會返回false。可以在for循環中用它來遍歷數據集。
默認的ResultSet是不能更新的,遊標也只能往下移。也就是說你只能從第一行到最後一行遍歷一遍。不過也可以創建可以回滾或者可更新的ResultSet,像下面這樣。
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
當生成ResultSet的Statement對象要關閉或者重新執行或是獲取下一個ResultSet的時候,ResultSet對象也會自動關閉。
可以通過ResultSet的getter方法,傳入列名或者從1開始的序號來獲取列數據。
6、ResultSet的不同類型
根據創建Statement時輸入參數的不同,會對應不同類型的ResultSet。如果你看下Connection的方法,你會發現createStatement和prepareStatement方法重載了,以支持不同的ResultSet和併發類型。
ResultSet對象有三種類型。
ResultSet.TYPE_FORWARD_ONLY:這是默認的類型,它的遊標只能往下移。
ResultSet.TYPE_SCROLL_INSENSITIVE:遊標可以上下移動,一旦它創建後,數據庫裡的數據再發生修改,對它來說是透明的。
ResultSet.TYPE_SCROLL_SENSITIVE:遊標可以上下移動,如果生成後數據庫還發生了修改操作,它是能夠感知到的。
ResultSet有兩種併發類型。
ResultSet.CONCUR_READ_ONLY:ResultSet是隻讀的,這是默認類型。
ResultSet.CONCUR_UPDATABLE:我們可以使用ResultSet的更新方法來更新裡面的數據。
閱讀更多 程序員小皮 的文章