深入淺出MyBatis:JDBC和MyBatis介紹

情情說發表於2018-03-25

最近在休陪產假,時間比較零碎,準備看2本書充實下,一本是「深入淺出MyBatis:技術原理與實踐」,一本是「RabbitMQ實戰:高效部署分散式訊息佇列」,為了加深記憶和理解,會進行整理、擴充套件和記錄。

看書的目標不是把所有的細節都記住,而是從整體上了解一個技術能做什麼,包含的特性、基本模組,實現原理和常見使用場景。

本篇分享MyBatis書籍的第一篇,首先回憶下JDBC的相關概念,瞭解Java提供的訪問資料庫最基本的方式,然後介紹下MyBatis的基本特性和核心元件,最後說下書的整體結構,瞭解後續文章的大致內容。

JDBC相關概念

Java程式都是通過JDBC連線資料庫的,通過SQL對資料庫程式設計,JDBC是由SUN公司提出的一些列規範,只定義了介面規範,具體實現由各個資料庫廠商去實現,它是一種典型的橋接模式。

橋接模式是一種結構型設計模式,它的主要特點是把抽象與行為實現分離開來,分別定義介面,可以保持各部分的獨立性以及應對他們的功能擴充套件。

JDBC規範

所謂規範,就是自己定義了標準介面,做了如下抽象:用Connection代表和資料庫的連線,用Statement執行SQL,用ResultSet表示SQL返回的結果,提供了對資料的便利。從Connection可以建立Statement,Statement執行查詢得到ResultSet。

上面說的Connection、Statement、ResultSet都應該是介面,具體實現由各個資料庫提供商提供。有了規範,可以通過統一的介面,訪問多種型別的資料庫,可隨便切換資料庫。

資料庫驅動

上面提到,介面的實現由各個廠商提供,那麼實現類的類名就會不統一,去建立Connection物件時,程式碼就會寫死某個實現類,切換資料庫時,就需要修改程式碼,這樣不太好。為了解決這個問題,抽象了Driver驅動的概念。

Connection con=MySqlConnectionImpl("127.0.0.1",3306,"mi_user",userName,pwd);
複製程式碼

每個資料庫都需要實現Driver介面,通過Driver可獲得資料庫連線Connection,通過反射機制動態建立。

Class.forName("com.mysql.jdbc.Drier");
複製程式碼

同一個程式可能訪問不同的資料庫,通過DriverManager來管理驅動,Driver在初始化的時候,需要註冊到DriverManager中。

DriverManager提供了一個getConnection方法,用於建立資料庫Connection:

Connection con=DriverManager.getConnection("127.0.0.1",3306,"mi_user",userName,pwd);
複製程式碼

如果有多個資料庫驅動,DriverManager如何區分呢,需要在資料庫連線url中指定,比如mysql需要新增jdbc:mysql字首:

String url= "jdbc:mysql://127.0.0.1:3306/mi_user";
Connection con=DriverManager.getConnection(url,userName,pwd)
複製程式碼
資料來源

資料來源DataSource包含連線池和連線池管理2個部分,習慣上稱為連線池。在系統初始化的時候,將資料庫連線作為物件儲存在記憶體中,當需要訪問資料庫時,從連線池中取出一個已建立的空閒連線物件。

使用資料來源,獲取其DataSource物件,通過該物件動態的獲取資料庫連線。另外,DataSource物件可以註冊到名字服務(JNDI)中,可以通過名字服務獲得DataSource物件,無需硬性編碼驅動。

DriverManager是JDBC1提供的,DataSource是JDBC2新增的功能,提供了更好的連線資料來源的方法。

對比Hibernate和MyBatis

通過上面的介紹,傳統的JDBC程式設計給我們帶來了連線資料庫的功能,但其工作量相對較大,首先連線,然後處理JDBC底層事務,處理資料型別,還要對可能產生的異常進行捕捉處理並正確的關閉資源。

實際工作中,很少使用JDBC進行程式設計,提出了ORM模型,主要解決資料庫資料和POJO物件的相互對映。

Hibernate和Mybatis都是ORM模型,Hibernate提供的是一種全表對映的模型,對JDBC的封裝程度比較高。但Hibernate也有不少缺點,列舉如下:

  • 全表對映帶來的不便,比如更新時需要傳送所有的欄位;
  • 無法根據不同的條件組裝不同的SQL;
  • 對多表關聯和複雜SQL查詢支援較差,需要自己寫SQL,返回後,需要自己將資料組裝為POJO;
  • 不能有效支援儲存過程;
  • 雖然有HQL,但效能較差,大型網際網路系統往往需要優化SQL,而Hibernate做不到。

大型網際網路環境中,靈活、SQL優化,減少資料的傳遞是最基本的優化方法,Hibernate無法滿足要求,而MyBatis提哦給你了靈活、方便的方式,是一個半自動對映的框架。

MyBatis需要手工匹配提供POJO、SQL和對映關係,而全表對映的Hibernate只需要提供POJO和對映關係。

MyBatis可以配置動態SQL,可以解決Hibernate的表名根據時間變化,不同的條件下列明不一樣的問題。可以優化SQL,通過配置決定SQL對映規則,也能支援儲存過程,對於一些複雜和需要優化效能的SQL的查詢它更加方便。

核心元件

核心元件主要包括以下幾個:

  • SqlSessionFactoryBuilder:會根據配置資訊或程式碼來生成SqlSessionFactory;
  • SqlSessionFactory:依靠工廠來生成SqlSession;
  • SqlSession:是一個既可以傳送SQL去執行並返回結果,也可以獲取Mapper的介面;
  • SQL Mapper:是MyBatis新設計的元件,由一個Java介面和XML檔案構成,需要給出對應的SQL和對映規則。它負責傳送SQL去執行,並返回結果。
構建SqlSessionFactory

每個MyBatis應用都是以SqlSessionFactory的例項為中心的,它的任務是建立SqlSession。SqlSesion類似於一個JDBC的Connection物件。

提供了2種方式建立SqlSessionFactory:一種是XML配置的方式,一種是程式碼的方式,推薦使用XML配置的方式。

定義mybatis-config.xml檔案如下:

<? xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
 <properties resource="application.properties">
 </properties>
 
 <!-- 定義別名 -->
 <typeAliases>
 <typeAlias alias="role" type="com.learn.chapter2.po.Role"/>
 </typeAliases>
 
 <!-- 定義資料庫資訊.預設使用development資料庫構建環境 -->
 <environments default="development">
    <environment id="development">
    <!-- 採用jdbc事務管理 -->
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>
 </environments>
 
 <!-- 定義對映器 -->
 <mappers>
 <mapper resource="com\learn\chapter2\mapper\roleMapper.xml"/>
 </mappers>
</configuration>
複製程式碼

建立SqlSessionFactory

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory  sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
複製程式碼
建立SqlSession

SqlSession是一個介面類,扮演者門面的作用,真正幹活的是Executor介面。需要保證每次用完正常關閉它。

SqlSession sqlSession=null;
try{
    sqlSession=sqlSessionFactory.openSession();
    //some code
    sqlSession.commit();
} catch(Exception ex){
    sqlSession.roolback();
} finally{
    if(sqlSession!=null){
        sqlSession.close();
    }
}
複製程式碼
對映器

對映器是由Java介面和XML檔案(或註解)共同組成的,作用如下:

  • 定義引數型別
  • 描述快取
  • 描述SQL語句
  • 定義查詢結果和POJO的對映關係

首先,定義Java介面:

public interface RoleMapper{
    public Role getRole(Long id);
}
複製程式碼

然後,定義對映XML檔案,RoleMapper.xml

<? xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
 
 <mapper namespace ="com.learn.chapter2.mapper.RoleMapper">
    <select id="getRole" paramterType="long" resultType="role" >
        select id,role_name as roleName , note from t_role where id=#{id}
    </select>
 </mapper>
複製程式碼

POJO物件Role的定義比較簡單,就不列出了。#{id}為這條SQL的引數,SQL列的別名和POJO的屬性名稱保持一致,會把這條語句的查詢結果自動對映到Role屬性上,這就是自動對映。

執行查詢

RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class);
Role role=roleMapper.getRole(1L);
String roleName=role.getRoleName();
複製程式碼
元件生命週期

SqlSessionFactory在MyBatis應用的整個生命週期中,每個資料庫只對應一個SqlSessionFactory,可以實現一個工具類,以單例模式獲取該物件。

SqlSession的生命週期在請求資料庫處理事務的過程中,它是一個執行緒不安全的物件,在涉及多執行緒的時候要特別當心。它存活於一個應用的請求和操作,可以執行多條SQL,保證事務的一致性。

Mapper的作用是傳送SQL,然後返回需要的結果,或者執行SQL修改資料庫的資料,所以它應該在一個SqlSession事務方法之內,如同JDBC中一條SQL語句的執行,它最大的範圍和SqlSession是相同的。

書的整體結構

本書分為3個部分,依次介紹了MyBatis的基礎應用、原理及外掛開發、實戰應用。

基礎應用

主要介紹如何高效地使用MyBatis:

  • MyBatis特性
  • 核心元件及其生命週期
  • MyBatis配置
  • 對映器
  • 動態SQL
MyBatis原理

深入原始碼理解MyBatis的內部執行原理以及外掛的開發方法和技巧:

  • 介紹MyBatis的解析和執行原理,將瞭解到SqlSession的構建方法,以及四大物件是如何工作的
  • 介紹MyBatis的外掛
實戰應用

主要講解MyBatis的一些實用的場景:

  • 介紹MyBatis-Spring,講解如何在Spring專案中整合MyBatis應用
  • 介紹MyBatis的實用場景,精選一些典型場景,解析每個場景下,開發人員需要注意避免的一些錯誤和效能上的損失

下篇會介紹MyBatis的相關配置,更好的配置MyBatis以適用於不同的業務場景,以及提供給我們的擴充套件。

歡迎掃描下方二維碼,關注我的個人微信公眾號 ~

情情說

相關文章