中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

發布時間:2021-10-19 17:32:44 來源:億速云 閱讀:93 作者:iii 欄目:編程語言

這篇文章主要講解了“全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式”吧!

1、Mybatis 是如何找到 SQL 語句的 ?

通過前面的學習,我們已經對 Mybatis 的架構設計以及核心數據層執行流程都非常了解,其實對于我們應用層的研發用戶來說,使用 Mybatis 框架的目的很簡單,就是希望通過它來消除原有 JDBC 的冗余代碼邏輯、減輕我們開發工作量、提升研發效率、以便于我們能夠專注于 SQL 的編寫。所以說到底,是我們寫 SQL,Mybatis 幫我們執行 SQL ,跟數據庫做交互,更簡單來說,我們和 Mybatis 的配合就5步:

1、我們編寫 SQL

2、發號施令(調用API)

3、Mybatis 找 SQL

4、Mybatis 執行 SQL

5、返回執行結果

看吧,Mybatis 實實在在是數據庫交互的好幫手呢,乖巧又高效,我們只需編寫好 SQL ,在程序應用中就可以隨處發號施令(調用API),讓 Mybatis 幫我們具體執行 SQL。但其實我們知道 Mybatis 默默做了許多事情,我們前面也都詳細剖析過的:

例如第1步編寫 SQL,其實 Mybatis 就要求我們必須提前完成信息配置 Config.xml 與 映射文件 Mapper.xml (后面注解道理相同)再開始編寫 SQL;

例如第2步發號施令,其實就是我們實際應用當中調用增刪改查接口( 好比sqlsession.selectList );

例如第4步執行 SQL,其實就是會話調用執行器,執行器調用語句處理器,語句處理器結合參數處理器與類型處理器最終底層通過 JDBC 與數據庫交互;

例如第5步返回執行結果,是 JDBC 返回的結果集并映射封裝,最終返回預期的封裝對象。

細心的你可能會發現,我們第3步沒說到,那第3步是做什么的呢:Mybatis 找 SQL

到此,開始我們本小結的研究主題:

Mybatis 是如何找到 SQL 語句的?

針對這個問題,我們首先細細回想,平日里我們的 SQL 語句都編寫在哪些地方呢?嗯 ~ 不出意外的話,我相信大家腦海里都會浮現兩個地方:一個是 XML 配置文件,另一個是 Java 注解

沒錯!假如使用 XML 配置方式則在 UserMapper.xml 配置文件中編寫 SQL 語句:

<mapper namespace="com.panshenlian.dao.UserDao">

    <!-- 查詢用戶列表 -->
    <select id="findAll" resultType="com.panshenlian.pojo.User" >
        select * from User 
    </select>
    
</mapper>

使用 XML 配置方式編寫 SQL,會把 XML 中的「 命名空間標識 + 語句塊 ID 」作為唯一的語句標識,這里的唯一語句標識為:

com.panshenlian.dao.UserDao.findAll

假如使用 Java 注解方式則在 UserDao 接口中編寫 SQL 語句:

public class UserDao {
   
    
    /** * 查詢用戶列表 * @return */
    @Select(value =" select * from User ")
    List<User> findAll();
    
}

使用 Java 注解方式編寫 SQL,會把接口中的「 接口全限定名 + 方法名 」作為唯一的語句標識,這里的唯一語句標識也是一樣:

com.panshenlian.dao.UserDao.findAll

其實,我們的 Mybatis 是支持使用 XML 配置方式和 Java 注解兩種方式來編寫 SQL 語句的,兩者沒有絕對的孰優孰劣,每個項目團隊都可以根據自身研發人員編碼習慣/能力、工程的耦合性要求、研發效能性價比等多方面綜合考慮之后去做選擇。畢竟無論我們使用哪種方式,目的都只是為了把實際需要執行的 SQL 準備好,供 Mybatis 跟數據庫交互時使用。

是這樣的,Mybatis 在啟動構建之初,會掃描我們編寫的 SQL 文件。假如你使用 XML 配置方式編寫 SQL,那么需要在 Config.xml 核心配置文件中指定映射器文件 mapper.xml (下面代碼演示第一種);如果你使用 Java 注解方式編寫 SQL ,那么需要在 Config.xml 核心配置文件中也指定加載使用了注解的Mapper接口(下面代碼演示第二種)。

<!-- 第一種:XML配置方式:指定映射器文件 -->
<mappers>
    <mapper resource="UserMapper.xml" />
</mappers>

<!-- 第二種:Java注解方式:指定映射器接口 -->
<mappers> 
    <mapper class="com.panshenlian.dao.UserDao"/>  
</mappers>

同樣無論你使用哪一種方式告訴 Mybatis 來掃描/構建,最終都會被統一加載到一個 SQL 語句集合的大池子里面,它是一個 Map 集合,以我們上面說的 唯一語句標識 作為集合的 key,以每一條 SQL 語句對象作為 value ,并且最終這個 SQL 語句 Map 集合的大池子,會作為一個屬性設置在全局配置 Configuration 上面,供我們 Mybatis 在整個應用周期里頭隨時使用。

看看,每一個 SQL 語句都實例成一個 MappedStatement 語句對象,并且這個 SQL 語句 Map 集合的大池子,會作為全局配置 Configuration 的屬性 mappedStatements 。

// Mybatis 全局配置對象
public class Configuration{
   
    
    // 存儲SQL語句的集合池 
    Map<String, MappedStatement> mappedStatements 
        = new StrictMap<MappedStatement>
}

基本簡單的 SQL 語句解析過程:

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

到這里,我相信有部分好奇的朋友還是想知道,那 Mybatis 是如何把我們編寫的每一條 SQL 語句加載到語句集合大池子的呢?又是怎么保證每條語句在集合大池子中的 Key 值(唯一語句標識)是唯一不會重復的呢?

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

嗯,我們抱著好奇的小腦袋,對這兩個疑問進行探索:

1、Mybatis 是如何把我們編寫的每一條 SQL 語句加載到語句集合大池子的呢?

首先,我們看看 Mybatis 在初始構建會話時,會通過加載核心配置文件,獲得會話工廠對象:

//加載核心配置文件
InputStream is = 
    Resources.getResourceAsStream("SqlMapConfig.xml");

// 獲得sqlSession工廠對象
SqlSessionFactory f = 
    new SqlSessionFactoryBuilder().build(is);

我們跟蹤了源代碼,發現會話工廠構建器 SqlSessionFactoryBuilder 的build() 邏輯中,在實現會話工廠實例構建的同時,會解析配置文件并封裝成全局配置對象 Configuration 和語句對象集合 MappedStatement 。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

用殊途同歸,來形容 XML 配置方式和 Java 注解方式編寫 SQL 并構建語句集合的過程再好不過了。

2、Mybatis 是怎么保證每條語句在集合大池子中的 Key 值(唯一語句標識)是唯一不會重復的呢??

根據第1個問題的分析結果,我們知道 SQL 語句最終會被存放在語句集合中,那這個語句集合是普通 Map 嗎?顯示不是,這個集合實例其實是 Mybatis 框架在 Configuration 全局配置對象中的一個靜態的匿名內部類 StrictMap,它繼承 HashMap ,重寫了 put() 方法,在 put() 中實現對 Key 值(唯一語句標識)的重復校驗。

// 全局配置
public class Configuration {
   
    
    // 靜態匿名內部類
    protected static class 
        StrictMap<V> extends HashMap<String, V> {
   
        
        // 重寫了put方法
        @Override 
    	public V put(String key, V value) {
   
            
          // 如果出現重復key則拋出異常
          if (containsKey(key)) {
   
            throw 重復異常;
          } 
    	} 
    }
}

所以,無論是使用 XML 配置方式還是 Java 注解方式,都必須保證每條 SQL 語句有一個 唯一的語句標識,否則在 Mybatis 啟動構建階段,就會收到來自 Mybatis 的解析異常,例如我在 UserMapper.xml 中設置兩個 findAll 語句。

<select id="findAll">
    select 1 from User
</select>

<select id="findAll">
    select * from User
</select>

不出意外,出現 Mybatis 解析 SQL 的異常警告:

// 異常定位很準確 --> 解析 mapper sql 時
### org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration.

// 哪個 mapper 文件呢 --> UserMapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'UserMapper.xml'

// 哪個 id 重復了呢 --> findAll
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.panshenlian.dao.IUserDao.findAll. please check UserMapper.xml and UserMapper.xml

好,到這里我們基本清晰,SQL 怎么存,并且怎么不重復的存,而且存在哪?那剩下的就很簡單,對于一個 Map 集合的取值,我相信大家都知道,無非就是通過 key 來取到存儲的 value 值。而 Mybatis 中這個語句集合的取值方式也是一樣通過 key 值來去,這個 key 呢,我們這里是每一條語句的 唯一語句標識 ,當我們調用會話 SqlSession 的增刪改查 API 的時候,就會傳遞這個唯一語句標識,告訴 Mybatis :“ 幫我們把這個 key 對應的語句對象的 SQL 執行一下吧 “ ,僅此而已。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

只不過,這里面當我們應用層的用戶調用增刪改查 API 的時候,我們到底是 **如何把 Key 值告知給 Mybatis 呢?**是 直接 告訴 Mybatis 呢?還是委婉的(通過代理方式)告訴 Mybatis 。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

這個就比較有意思了,也是我們第3部分主題要講解的內容,我們下面會細說,先看第2部分主題吧~

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

2、為什么有 Dao 層 ?

在軟件開發中,為了方便應用程序的研發與維護,一般我們都會使用清晰合理的框架模式來規范開發行為,提高同模塊內聚性,減低異模塊耦合性,例如 MVC、MVP、MVVM 等,而其中 MVC(Model-View-Controller) 則是 Java 語言中應用最廣泛的分層框架模式。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

對于 MVC 分層模式,其實最早的設計來源于桌面應用程序,一般 M 代表業務模型 Model,V 代表視圖界面 view,C 代表控制器 Controller ,一般的:

View (視圖層):視圖層直接面向用戶/終端,提供給用戶/終端的指令輸入或界面操作請求。

Controller (控制層):控制層負責接收 “視圖層” 的指令或操作請求,并轉移分派至 “模型層”,接收到 “模型層” 的返回結果之后,會同步傳送回 “視圖層”,達到控制/紐帶的作用。

Model (模型層):模型層是核心的數據信息處理層,分為業務邏輯處理與數據持久化處理,模型層接收來自 “控制層” 的請求,并通過邏輯運算與數據轉換,再把處理結果返回到 “控制層”。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

從程序編碼角度看,我們使用 MVC 的主要目的就是將 M 層與 V 層的實現代碼分離,方便代碼分層設計與維護;從結果形態角度分析,其實 M 層與 V 層可以理解為相同信息(或物質)的不同表現形態,類比水與冰、或水與氣(可能不恰當,But 我確實理解為信息/物質形態轉移),而 C 層的存在目的就是為了連接轉移 M 層與 V 層,保證 M 層與 V 層的同步/更新。

那有好奇的朋友就想知道,上面這介紹的 MVC 框架模式,跟我們 Dao 層有什么關系呢?

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

那必須有關系!

我們知道在 MVC 框架模式中,模型層 Model 是核心的數據信息處理層,包括業務邏輯處理與數據持久化處理,其中業務邏輯處理我們劃為 Service 模塊,負責具體業務需求對應的運算邏輯;數據持久化處理我們劃為 Dao 模塊(全稱 Data Access Object ,即數據訪問對象),負責與數據庫交互,連接 Service 模塊與數據庫。所以只要是跟數據庫打交道,我們的 Dao 層就必不可少!

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

到這里,我相信很多朋友會聯想到,Dao 模塊是負責數據持久化處理 ,而我們的 Mybatis 不就是一個持久層框架嗎?沒錯,所以跟數據庫打交道的活,Mybatis 框架絕對是能全權負責,所以當我們的項目應用集成 Mybatis 框架之后, Mybatis 的增刪改查等 API 就基本在 Dao 模塊中使用,并且接口調用與代碼實現也是極為簡單便捷。

第3部分,我們講講本文的關鍵主題 “ Dao 層的兩種實現方式:傳統與代理 ”。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

3、Dao 層的兩種實現方式:傳統與代理

有了前面兩點作為基礎,我們的第三個主題《 Dao 層的兩種實現方式:傳統與代理 》的內容講解會讓大家很容易接受,因為我們在第一部分主題中花大篇幅闡明 Mybatis 是如何找到 SQL 語句的,讓大家對于 SQL 語句的尋找有了全面的了解,所以我在此處先提前跟大家劇透:Dao 層的兩種實現方式:傳統與代理 ,可以粗糙的理解為他兩僅僅在SQL 語句的 尋找方式執行對象 上存在區別而已。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

我們先簡單看看我們一般的工程目錄結構簡例(掐頭去尾只留下基本的 MVC 目錄骨架)。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

一般 Dao 層 傳統上 的代碼實現方式:

1、編寫UserDao接口

public interface UserDao {
    
    List<User> findAll() ; 
}

2、編寫UserDaoImpl實現

public class UserDaoImpl implements UserDao {
    
    
    @Override
    public List<User> findAll() {
    
        
        //加載核心配置文件
        InputStream is = Resources.getResourceAsStream("config.xml");

        // 獲得sqlSession工廠對象
        SqlSessionFactory fy = new SqlSessionFactoryBuilder().build(is);

        //獲得sqlSession對象
        SqlSession sqlSession = fy.openSession();

        // 執行sql語句
        List<User> userList = sqlSession.selectList("dao.UserDao.findAll");
        
        return userList;
       
    }
}

3、編寫 UserMapper.xml

<mapper namespace="dao.UserDao">

    <select id="findAll">
        select * from User
    </select>

</mapper>

4、Dao 層調用 (通過應用程序的 Service 層調用或者直接使用 Junit 框架進行測試)

// Service 服務層調用 
// 或
// Junit 測試框架測試

@Test 
public void tesDaoMethod(){
   
    UserDao userDao = new UserDaoImpl(); 
	List<User> userList = userDao.findAll();
    System.out.println(userList);
}

以上調用結果可以獲取到所有 User 記錄,這種通過在 Dao層定義接口、并創建 Dao 層接口實現類的方式,我們一般稱之為 Dao 層的傳統實現方式,此方式會構建一個接口實現類去作為 Dao 層的執行對象,并且對于 SQL 語句的找尋方式特別簡單直接,直接指定唯一語句標識,Java 文件中存在硬編碼, 例如本示例中的 SQL 語句唯一標識為: dao.UserDao.findAll。

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

介紹完傳統的開發實現方式,我們說說 Dao 層的代理開發實現方式吧,首先 Dao 層的代理開發方式有什么特別呢?

首先代理開發實現方式只需我們編寫 Dao 接口而不需要編寫實現類。

那么既然不用編寫實現類,是不是會有一些其它方面的約束呢?

那是當然了,這種代理開發實現方式,要求我們的接口與配置文件 Mapper.xml 需要遵循一些規范:

1) Mapper.xml 文件中的 namespace 與 mapper 接口的全限定名相同
2) Mapper 接口方法名和 Mapper.xml 中定義的每個 statement 的 id 相同
3) Mapper 接口方法的輸入參數類型和 mapper.xml 中定義的每個 sql 的 parameterType 的類型相同
4) Mapper 接口方法的輸出參數類型和 mapper.xml 中定義的每個 sql 的 resultType 的類型相同

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

由于代理開發實現方式與 Mapper 配置緊密關聯,故此我們也稱之為 Mapper 接口開發方法,之所以不需要編寫實現類的原因是其底層創建了 Dao 接口的動態代理對象,代理對象本身會構建有 Dao 接口的方法體, Dao 層 代理實現方式 的代碼實現方式:

1、編寫UserDao接口

public interface UserDao {
    
    User findOne( int userId ) ; 
}

2、編寫 UserMapper.xml

<mapper namespace="dao.UserDao">
    <select id="findOne" parameterType="int" resultType="user">
    	select * from User where id =#{id}
    </select>
</mapper>

3、Dao 層調用 (通過應用程序的 Service 層調用或者直接使用 Junit 框架進行測試)

// Service 服務層調用 
// 或
// Junit 測試框架測試

@Test 
public void tesDaoMethod(){
   
    
    //加載核心配置文件
    InputStream is = Resources.getResourceAsStream("config.xml");

    // 獲得sqlSession工廠對象
    SqlSessionFactory fy = new SqlSessionFactoryBuilder().build(is);

    //獲得sqlSession對象
    SqlSession sqlSession = fy.openSession(); 

    //獲得MyBatis框架生成的 UserMapper接口的代理類
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
    
    //代理類執行SQL
    User user = userMapper.findById(1); 
    System.out.println(user); 
    sqlSession.close(); 
}

以上調用結果可以獲取到了指定 ID 的 User 記錄,此方式通過代理執行實際 SQL 語句,由于 Dao 接口與 Mapper.xml 配置已經約定好規范,所以不需要在調用接口時指定唯一語句標識,Java 文件中也不會存在硬編碼問題。

到這里,就會有部分朋友疑惑? sqlSession 會話通過 getMapper 獲取接口代理類之后去調用接口方法,那到底實際執行接口方法的時候,Mybatis 的代理在代碼邏輯上是怎么跟 mapper.xml 配置文件中的 SQL 語句對應匹配起來的呢?

全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式

上圖黑色 ① ~ ⑥ ,是構建 Dao 代理對象的實際過程,基本就是生成代理對象的過程,其中 MapperProxy 代理類本身實現了 InvocationHandler 接口,所以符合一個代理類的要求,MapperProxy 代理實例最終是指派 MapperMethod 對象進行語句分發執行,包含增刪改查等操作。

上圖紅色 ① ~ ③ ,是代理對象在執行實際接口時根據接口全限定名去 SQL 語句集合池查找 SQL 具體語句的過程。

// 實際語句執行方法對象
public class MapperMethod{
   
    // 根據指令類型分配執行SQL
	public Object execute(SqlSession sqlSession, Object[] args) {
   
        switch (command.getType()) {
   
      		case INSERT: sqlSession.insert(接口語句ID); break;
      		case UPDATE: sqlSession.update(接口語句ID); break;
      		case DELETE: sqlSession.insert(接口語句ID); break;
      		case SELECT: sqlSession.select(接口語句ID); break;
        }
	}   
}

感謝各位的閱讀,以上就是“全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式”的內容了,經過本文的學習后,相信大家對全息視角看Dao層兩種實現方式之有哪些傳統方式與代理方式這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阜宁县| 上思县| 莱阳市| 格尔木市| 陈巴尔虎旗| 苍南县| 山东| 且末县| 清远市| 萍乡市| 清水河县| 房产| 汝阳县| 宣武区| 寿宁县| 司法| 林州市| 聂拉木县| 赤峰市| 建阳市| 安多县| 连山| 天津市| 乌审旗| 枣庄市| 泸州市| 靖远县| 长岛县| 砀山县| 宣城市| 应用必备| 布尔津县| 稷山县| 玉屏| 县级市| 巴中市| 邹城市| 濉溪县| 鄂托克前旗| 汽车| 象山县|