在之前的文章中,我為大家介紹了 Mybatis 的詳細用法,算是基礎教程。
詳細連結:Mybatis 基礎教程
言歸正傳,只懂基礎可不行,接下來將給大家帶來高階的原始碼解析教程,從淺入深,通過原始碼解析,圖例結合,抽絲剝繭,讓大家看的不吃力,並且能夠深刻理解 Mybatis 這個框架的底層實現原理,讓大家學到的不僅僅是這個框架用法,而是通過這個框架理解其設計思想。
1、JDBC
我相信所有開發者第一次與資料庫打交道時,就是通過 JDBC 來實現的,第一次通過程式獲取到資料庫中的資料時,那種高興,那種吃驚,反正我依稀歷歷在目。
什麼是 JDBC:JDBC 是Java與資料庫互動的API,用來規範客戶端程式如何來訪問資料庫的應用程式介面。
通常分為兩組API:
①、面向Java應用程式開發人員的API,是一個標準的API,且不同資料庫具有不同的實現。
②、面向資料庫驅動開發人員,是前者的底層支援。
因為大家都是Java開發人員,這裡我們就介紹第一組API。
JDBC API主要位於JDK中的java.sql包中(之後擴充套件的內容位於javax.sql包中)
下面介紹幾個關鍵的介面,注意這都是JDK內部提供的一些介面,具體實現得看具體的資料庫驅動,比如MySQL,我們通常會在maven或gradle配置mysql-connectior-java ,下面介面的具體實現就在其中。
①、Driver:驅動程式,會將自身載入到DriverManager中去.
②、DriverManager:負責載入各種不同驅動程式(Driver),並根據不同的請求,向呼叫者返回相應的資料庫連線(Connection)。
③、Connection:資料庫連線,負責與進行資料庫間通訊,SQL執行以及事務處理都是在某個特定Connection環境中進行的。可以產生用以執行SQL的Statement。
④、Statement:用來執行SQL查詢和更新(針對靜態SQL語句和單次執行)。
⑤、PreparedStatement:用來執行包含動態引數的SQL查詢和更新(預編譯,在伺服器端編譯,允許重複執行以提高效率)。
⑥、CallableStatement:用來呼叫資料庫中的儲存過程。
⑦、ResultSet:用來儲存資料庫查詢操作返回的結果。
⑧、SQLException:表示在資料庫連線的建立、SQL語句的執行、關閉等過程中發生了異常。
2、完整的互動過程
下面,我們通過JDBC來完成一次資料庫查詢操作,步驟如下:
①、載入資料庫驅動
②、獲取資料庫連線(通過資料庫URL,使用者名稱,密碼)
③、定義SQL語句
④、通過資料庫連線,建立 Statement 物件或者 PreparedStatement 物件
⑤、通過 Statement 物件執行 SQL 語句,得到結果集 ResultSet 物件
⑥、讀取 ResultSet 物件,轉換成我們要的 JavaBean
⑦、關閉資料庫連線、Statement、ResultSet等物件,釋放相關資源
程式碼實現如下:
- package com.itcoke.bean;
- public class Person {
- private Long pid;
- private String pname;
- private Integer page;
- public Long getPid() {
- return pid;
- }
- public void setPid(Long pid) {
- this.pid = pid;
- }
- public String getPname() {
- return pname;
- }
- public void setPname(String pname) {
- this.pname = pname;
- }
- public Integer getPage() {
- return page;
- }
- public void setPage(Integer page) {
- this.page = page;
- }
- @Override
- public String toString() {
- return "Person{" +
- "pid=" + pid +
- ", pname='" + pname + '\'' +
- ", page=" + page +
- '}';
- }
- }
- package com.itcoke.jdbc;
- import com.itcoke.bean.Person;
- import java.sql.*;
- import java.util.ArrayList;
- import java.util.List;
- public class JDBCUtils {
- //MySQL資料庫驅動,注意多了一個cj,com.mysql.jdbc.Driver和mysql-connector-java 5一起用
- public static String driverClass = "com.mysql.cj.jdbc.Driver";
- //MySQL使用者名稱
- public static String userName = "root";
- //MySQL密碼
- public static String passWord = "root1234";
- //MySQL URL
- public static String url = "jdbc:mysql://localhost:3306/mybatis-study";
- //定義資料庫連線
- public static Connection conn = null;
- //定義宣告資料庫語句,使用 預編譯宣告 PreparedStatement提高資料庫執行效能
- public static PreparedStatement ps = null;
- //定義返回結果集
- public static ResultSet rs = null;
- public static List<Person> selectPersonByName(String pname){
- List<Person> personList = new ArrayList<>();
- try {
- // 1、載入資料庫驅動
- Class.forName(driverClass);
- // 2、獲取資料庫連線
- conn = DriverManager.getConnection(url,userName,passWord);
- // 3、定義 sql 語句,?表示佔位符
- String sql = "select * from person where pname=?";
- // 4、獲取預編譯處理的statement
- ps = conn.prepareStatement(sql);
- //設定sql語句中的引數,第一個為sql語句中的引數的?(從1開始),第二個為設定的引數值
- ps.setString(1, "itcoke");
- // 5、向資料庫發出 sql 語句查詢,並返回結果集
- rs = ps.executeQuery();
- while(rs.next()){
- // 6、讀取ResultSet,轉換成我們要的物件
- Person person = new Person();
- person.setPid(rs.getLong("pid"));
- person.setPname(rs.getString("pname"));
- personList.add(person);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }finally{
- // 7、關閉資料庫連線
- if(rs!=null){
- try {
- rs.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if(ps!=null){
- try {
- ps.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if(conn!=null){
- try {
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- return personList;
- }
- public static void main(String[] args){
- List<Person> personList = JDBCUtils.selectPersonByName("itcoke");
- System.out.println(personList);
- }
- }
PS:資料庫名稱為 mybatis-study,表為 person
3、缺點分析
①、問題一:每執行一次增刪改查,就要建立連線,關閉連線,頻繁的獲取連線和關閉連線,會造成資料庫資源浪費,影響資料庫效能。
設想解決:使用資料庫連線池管理資料庫連線
②、問題二:將 sql 語句硬編碼到程式中,如果sql語句修改了,那麼需要重新編譯 Java 程式碼,不利於系統維護
設想解決:將 sql 語句可配置化,比如設定到 xml 檔案中,這樣即使 sql 語句變化了,我們也不需要對 Java 程式碼進行修改
③、問題三:在 PreparedStatement 中設定引數,對佔位符設定值都是硬編碼在Java程式碼中,不利於系統維護
設想解決:將 sql 語句以及佔位符和引數都配置到 xml 檔案中
④、問題四:從 resultset 中遍歷結果集時,對錶的欄位存在硬編碼,不利於系統維護
設想解決:將查詢的結果集自動對映為 Java 物件
⑤、問題五:重複性程式碼特別多,包括建立建立,載入驅動等
設想解決:抽取封裝公共程式碼
⑥、問題六:沒有快取,如果存在資料量大,且頻繁查詢的情況,這種方式效能特別低
設想解決:整合快取框架去操作資料庫
⑦、問題七:sql 的移植性不好,如果換個資料庫,那麼sql 語句可能要重寫
設想解決:在 JDBC 和 資料庫之間插入第三方框架,用第三方去生成 sql 語句,遮蔽資料庫的差異
4、ORM框架
為了解決上面這些缺點,ORM(Object Relational Mapping,物件-關係對映)框架應運而生。
ORM 模型就是資料庫的表和Java物件的對映關係模型,它主要解決資料庫資料和Java物件的相互對映,通過對映關係,我們可以簡單而迅速的把資料庫資料轉換成Java物件,從而讓開發人員無需對資料庫相關知識深入瞭解,便可以操作資料庫資料。
當前市面上比較主流的ORM框架包括 Hibernate、Mybatis、Spring JDBC 等等,各有優缺點,這裡可樂不做詳細介紹,本系列文章主要是介紹當前使用最廣泛的 ORM框架——Mybatis。
其更輕量、更可控的特性,比較適合當前主流業務,特別是大資料量、高併發的場景。
5、小結
本文我們介紹了JDBC直接操作資料庫的一些問題,引申出解決此類問題的ORM框架,其中 Mybatis 是其中的佼佼者,
那麼為什麼 Mybatis 能夠解決 JDBC 直接操作資料庫的痛點?它又是如何實現的呢?
不要走開,我們下篇文章更精彩!