(轉)MyBatis & MyBatis Plus


(二期)3、mybatis與mybatis plus

【課程三】mybatis ...運用.xmind0.1MB

【課程三】mybatis...機制.xmind0.2MB

【課程三】mybatis與jdbc.xmind0.2MB

【課程三】多數據源處理.xmind49.4KB

【課程三】數據庫...字段.xmind38.4KB

【課程三預習】myb...plus.xmind73.9KB

 

 

講課順序:

  • mybatis基本概念
  • jdbc與mybatis關系
  • mybatis的主要組件
  • mybatis的二級緩存
  • mybatis如何獲取數據庫中的表、字段
  • mybatis的多數據源處理
  • mybatis的讀寫分離
  • 一個簡易的手寫mybatis
  • mybatis plus的簡單運用

問題准備:

MyBatis基本概念

MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。

jdbc與mybatis

需要先注冊驅動和數據庫信息、操作Connection、通過statement對象執行SQL,將結果返回給resultSet,然后從resultSet中讀取數據並轉換為pojo對象,最后需要關閉數據庫相關資源。而且還需要自己對JDBC過程的異常進行捕捉和處理

 

MyBatis對JDBC的封裝很好,幾乎可以取代Jdbc。

MyBatis使用SqlSessionFactoryBuilder來連接完成JDBC需要代碼完成的數據庫獲取和連接,減少了代碼的重復。JDBC將SQL語句寫到代碼里,屬於硬編碼,非常不易維護,MyBatis可以將SQL代碼寫入xml中,易於修改和維護。JDBC的resultSet需要用戶自己去讀取並生成對應的POJO,MyBatis的mapper會自動將執行后的結果映射到對應的Java對象中。

三個組件

SqlSessionFactoryBuilder與SqlSessionFactory、SqlSession

 

每個基於 MyBatis 的應用都是以一個 SqlSessionFactory 的實例為中心的。SqlSessionFactory 的實例可以通過 SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置文件或一個預先定制的 Configuration 的實例構建出 SqlSessionFactory 的實例。

 

既然有了 SqlSessionFactory ,顧名思義,我們就可以從中獲得 SqlSession 的實例了。SqlSession 完全包含了面向數據庫執行 SQL 命令所需的所有方法。你可以通過 SqlSession 實例來直接執行已映射的 SQL 語句。

 

作用域:

SqlSessionFactoryBuilder

這個類可以被實例化、使用和丟棄,一旦創建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 實例的最佳作用域是方法作用域(也就是局部方法變量)。你可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實例,但是最好還是不要讓其一直存在以保證所有的 XML 解析資源開放給更重要的事情。

 

SqlSessionFactory

SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由對它進行清除或重建。使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重復創建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是應用作用域。有很多方法可以做到,最簡單的就是使用單例模式或者靜態單例模式。

 

SqlSession

每個線程都應該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域。絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。也絕不能將 SqlSession 實例的引用放在任何類型的管理作用域中,比如 Servlet 架構中的 HttpSession。如果你現在正在使用一種 Web 框架,要考慮 SqlSession 放在一個和 HTTP 請求對象相似的作用域中。換句話說,每次收到的 HTTP 請求,就可以打開一個 SqlSession,返回一個響應,就關閉它。這個關閉操作是很重要的,你應該把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。下面的示例就是一個確保 SqlSession 關閉的標准模式:

原理

mybatis的二級緩存
一級緩存

在應用運行過程中,我們有可能在一次數據庫會話中,執行多次查詢條件完全相同的SQL,MyBatis提供了一級緩存的方案優化這部分場景,如果是相同的SQL語句,會優先命中一級緩存,避免直接對數據庫進行查詢,提高性能。具體執行過程如下圖所示。

  • 一級緩存數據庫會話內部共享
一級緩存工作流程

一級緩存的工作流程是怎樣的呢?我們從源碼層面來學習一下。

一級緩存執行的時序圖,如下圖所示。

 

二級緩存

在日常工作中,開發人員多數情況下是使用MyBatis的默認緩存配置,但是MyBatis緩存機制有一些不足之處,在使用中容易引起臟數據,形成一些潛在的隱患。

 

在上文中提到的一級緩存中,其最大的共享范圍就是一個SqlSession內部,如果多個SqlSession之間需要共享緩存,則需要使用到二級緩存。開啟二級緩存后,會使用CachingExecutor裝飾Executor,進入一級緩存的查詢流程前,先在CachingExecutor進行二級緩存的查詢,具體的工作流程如下所示。

二級緩存開啟后,同一個namespace下的所有操作語句,都影響着同一個Cache,即二級緩存被多個SqlSession共享,是一個全局的變量。

當開啟緩存后,數據的查詢執行的流程就是 二級緩存 -> 一級緩存 -> 數據庫。

 

  • Mybatis全局配置中啟用二級緩存配置
<setting name="cacheEnabled" value="true"/>
  • 在對應的Mapper.xml中配置cache節點
<mapper namespace="userMapper">
    <cache />
    <result ... />
    <select ... />
</mapper>
  • 在對應的select查詢節點中添加useCache=true
<select id="findUserById" parameterType="int" resultMap="user" useCache="true">
    select * from users where id=#{id};
</select>

 

 

集成ehcache做二級緩存步驟:

第一步:導入pom

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version>
</dependency> 

 

第二步:配置ehcache

1、ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <diskStore path="java.io.tmpdir/Tmp_EhCache" />
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
                  timeToIdleSeconds="0" timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LRU" />
    <cache name="content"
           maxEntriesLocalHeap="200"
           timeToLiveSeconds="3600">
    </cache>
</ehcache> 

2、application.properties中打開ehcache支持

spring.cache.ehcache.config=classpath:ehcache.xml

 

第三步:mybatis的xml中使用ehcache

<cache type="org.mybatis.caches.ehcache.EhcacheCache" >
     <!--當緩存閑置n秒后銷毀 -->
     <property name="timeToIdleSeconds" value="3600"/>
     <!--當緩存存活n秒后銷毀-->
     <property name="timeToLiveSeconds" value="3600"/>
     <property name="maxEntriesLocalHeap" value="1000"/>
     <property name="maxEntriesLocalDisk" value="10000000"/>
     <property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
mybatis如何獲取數據庫中的字段
原理

information_schema數據庫是MySQL自帶的,它提供了訪問數據庫元數據的方式。什么是元數據呢?元數據是關於數據的數據,如數據庫名或表名,列的數據類型,或訪問權限等。有些時候用於表述該信息的其他術語包括“數據詞典”和“系統目錄”。

 

在MySQL中,把 information_schema 看作是一個數據庫,確切說是信息數據庫。其中保存着關於MySQL服務器所維護的所有其他數據庫的信息。如數據庫名,數據庫的表,表欄的數據類型與訪問權 限等。在INFORMATION_SCHEMA中,有數個只讀表。它們實際上是視圖,而不是基本表,因此,你將無法看到與之相關的任何文件。

 

information_schema表說明

SCHEMATA表:提供了當前mysql實例中所有數據庫的信息。是show databases的結果取之此表。

TABLES表:提供了關於數據庫中的表的信息(包括視圖)。詳細表述了某個表屬於哪個schema,表類型,表引擎,創建時間等信息。是show tables from schemaname的結果取之此表。

COLUMNS表:提供了表中的列信息。詳細表述了某張表的所有列以及每個列的信息。是show columns from schemaname.tablename的結果取之此表。

STATISTICS表:提供了關於表索引的信息。是show index from schemaname.tablename的結果取之此表。

USER_PRIVILEGES(用戶權限)表:給出了關於全程權限的信息。該信息源自mysql.user授權表。是非標准表。

SCHEMA_PRIVILEGES(方案權限)表:給出了關於方案(數據庫)權限的信息。該信息來自mysql.db授權表。是非標准表。

TABLE_PRIVILEGES(表權限)表:給出了關於表權限的信息。該信息源自mysql.tables_priv授權表。是非標准表。

COLUMN_PRIVILEGES(列權限)表:給出了關於列權限的信息。該信息源自mysql.columns_priv授權表。是非標准表。

CHARACTER_SETS(字符集)表:提供了mysql實例可用字符集的信息。是SHOW CHARACTER SET結果集取之此表。

COLLATIONS表:提供了關於各字符集的對照信息。

COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用於校對的字符集。這些列等效於SHOW COLLATION的前兩個顯示字段。

TABLE_CONSTRAINTS表:描述了存在約束的表。以及表的約束類型。

KEY_COLUMN_USAGE表:描述了具有約束的鍵列。

ROUTINES表:提供了關於存儲子程序(存儲程序和函數)的信息。此時,ROUTINES表不包含自定義函數(UDF)。名為“mysql.proc name”的列指明了對應於INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。

VIEWS表:給出了關於數據庫中的視圖的信息。需要有show views權限,否則無法查看視圖信息。

TRIGGERS表:提供了關於觸發程序的信息。必須有super權限才能查看該表

 

 

查找當前數據庫的表信息:

第一種方法:

select * from information_schema.TABLES where TABLE_SCHEMA=(select database())

第二種方法:

#獲取表信息
show table status 

 

查找當前表的所有字段信息:

第一種方法:

select * from information_schema.COLUMNS where TABLE_SCHEMA = (select database()) and TABLE_NAME=#{tableName}

第二種方法:

show full fields from `student`;
mybatis的多數據源處理
單獨使用mybatis的多數據源處理

配置多個environment,生產sessionFactory的時候指定environment即可實現多數據源。

<environments default="development">
    <environment id="development">
        <!--使用默認的JDBC事務管理-->
        <transactionManager type="JDBC"/>
        <!--使用連接池-->
        <dataSource type="POOLED">
            <!--這里會替換為local-mysql.properties中的對應字段的值-->
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>
 
          
    <environment id="development2">
        <!--使用默認的JDBC事務管理-->
        <transactionManager type="JDBC"/>
        <!--使用連接池-->
        <dataSource type="POOLED">
            <!--這里會替換為local-mysql.properties中的對應字段的值-->
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url2}"/>
            <property name="username" value="${username2}"/>
            <property name="password" value="${password2}"/>
        </dataSource>
    </environment>
</environments>
集成spring的多數據源處理

1、通過掃描包區分

git demo: https://gitee.com/lv-success/git-second/tree/master/course-3-mybatis/springBootMybatisMulidatasource

 

2、通過動態數據源區分

一般使用注解的形式,這里先留着,后面的renren-fast項目

mybatis的讀寫分離

原理:

和多數據源處理差不多,mybatis做讀寫分離也有多種方法。通過攔截發起請求的方法或執行的sql來自動判斷需要的數據源!

 

1、攔截發起操作的方法名

需要自己約定增刪改查的前綴,然后根據前綴選擇數據源!

git demo:https://gitee.com/lv-success/git-second/tree/master/course-3-mybatis/bounterMybatis

 

2、攔截發起操作的sql

git demo:https://github.com/shawntime/shawn-rwdb

一個簡易的手寫mybatis
邏輯整理

  • 1.讀取xml文件,建立連接

從圖中可以看出,MyConfiguration負責與人交互。待讀取xml后,將屬性和連接數據庫的操作封裝在MyConfiguration對象中供后面的組件調用。本文將使用dom4j來讀取xml文件,它具有性能優異和非常方便使用的特點。

 

  • 2.創建SqlSession,搭建Configuration和Executor之間的橋梁

我們經常在使用框架時看到Session,Session到底是什么呢?一個Session僅擁有一個對應的數據庫連接。類似於一個前段請求Request,它可以直接調用exec(SQL)來執行SQL語句。從流程圖中的箭頭可以看出,MySqlSession的成員變量中必須得有MyExecutor和MyConfiguration去集中做調配,箭頭就像是一種關聯關系。我們自己的MySqlSession將有一個getMapper方法,然后使用動態代理生成對象后,就可以做數據庫的操作了。

 

  • 3.創建Executor,封裝JDBC操作數據庫

Executor是一個執行器,負責SQL語句的生成和查詢緩存(緩存還沒完成)的維護,也就是jdbc的代碼將在這里完成,不過本文只實現了單表,有興趣的同學可以嘗試完成多表。

 

  • 4.創建MapperProxy,使用動態代理生成Mapper對象

我們只是希望對指定的接口生成一個對象,使得執行它的時候能運行一句sql罷了,而接口無法直接調用方法,所以這里使用動態代理生成對象,在執行時還是回到MySqlSession中調用查詢,最終由MyExecutor做JDBC查詢。這樣設計是為了單一職責,可擴展性更強。

 

mybatis plus的簡單運用

官方地址:

https://gitee.com/lv-success/git-second/tree/master/course-3-mybatis/mybatisPlusDemo

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM