日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

1.Executor

Executor 是 MyBatis 的核心接口之一,其中定義了數據庫操作的基本方法。在實際應用中經常涉及的 SqISession 接口的功能,都是基于 Executor 接口實現的。

 

MyBatis源碼解析

 

BaseExecutor 是一個實現了 Executor 接口的抽象類,它實現了 Executor 接口的大部分方法。BaseExecutor 中主要提供了緩存管理和事務管理的基本功能,繼承 BaseExecutor 的子類只要實現四個基本方法來完成數據庫的相關操作即可,這四個方法分別是:doUpdate()方法、doQuery()方法、doQueryCursor()方法、doFlushStatement()方法。


 // 一級緩存,用于緩存該Executor對象查詢結果集映射得到的結果對象
  protected PerpetualCache localCache;
  // 一級緩存,用于緩存輸出類型的參數
  protected PerpetualCache localOutputParameterCache;

常見的應用系統中,數據庫是比較珍貴的資源,很容易成為整個系統的瓶頸。在設計和維護系統時,會進行多方面的權衡,并且利用多種優化手段,減少對數據庫的直接訪問。

使用緩存是一種比較有效的優化手段,使用緩存可以減少應用系統與數據庫的網絡交互、減少數據庫訪問次數、降低數據庫的負擔、降低重復創建和銷毀對象等一系列開銷,從而提高整個系統的性能。

MyBatis 提供的緩存功能,分別為一級緩存和二級緩存。BaseExecutor 主要實現了一級緩存的相關內容。一級緩存是會話級緩存,在 MyBatis 中每創建一個 SqlSession 對象,就表示開啟一次數據庫會話。在一次會話中,應用程序可能會在短時間內(一個事務內),反復執行完全相同的查詢語句,如果不對數據進行緩存,那么每一次查詢都會執行一次數據庫查詢操作,而多次完全相同的、時間間隔較短的查詢語句得到的結果集極有可能完全相同,這會造成數據庫資源的浪費。

為了避免上述問題,MyBatis 會在 Executor 對象中建立一個簡單的一級緩存,將每次查詢的結果集緩存起來。在執行查詢操作時,會先查詢一級緩存,如果存在完全一樣的查詢情況,則直接從一級緩存中取出相應的結果對象并返回給用戶,減少數據庫訪問次數,從而減小了數據庫的壓力。

一級緩存的生命周期與 SqlSession 相同,其實也就與 SqISession 中封裝的 Executor 對象的生命周期相同。當調用 Executor 對象的 close()方法時(斷開連接),該 Executor 對象對應的一級緩存就會被廢棄掉。一級緩存中對象的存活時間受很多方面的影響,例如,在調用 Executor 的 update()方法時,也會先請空一級緩存。一級緩存默認是開啟的,一般情況下,不需要用戶進行特殊配置。

CachingExecutor 中為 Executor 對象增加了二級緩存相關功能,而 mybatis 的二級緩存在實際使用中往往利大于弊,被 redis 等產品所替代

二級緩存mApper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession去操作數據庫得到數據會存在二級緩存區域多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。

二級緩存是多個SqlSession共享的,其作用域是mapper的同一個namespace,第一次執行完畢會將數據庫中查詢的數據寫到緩存(內存),第二次會從緩存中獲取數據將不再從數據庫查詢,從而提高查詢效率。

Mybatis默認沒有開啟二級緩存需要在setting全局參數中配置開啟二級緩存。

如果緩存中有數據就不用從數據庫中獲取,大大提高系統性能。

2.StatmentHandler

StatementHandler 接口是 MyBatis 的核心接口之一,它完成了 MyBatis 中最核心的工作,也是 Executor 接口實現的基礎。
StatementHandler 接口中的功能很多,例如創建 Statement 對象,為 SQL 語句綁定實參,執行 select、insert、update、delete 等多種類型的 SQL 語句,批量執行 SQL 語句,將結果集映射成結果對象。

public enum StatementType {
  STATEMENT, PREPARED, CALLABLE
}
MyBatis源碼解析

 

RoutingStatementHandler 使用了策略模式,RoutingStatementHandler 是策略類,而 SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler 則是實現了具體算法的實現類,RoutingStatementHandler 對象會根據 MappedStatement 對象的 StatementType 屬性值選擇使用相應的策略去執行。

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // RoutingStatementHandler的作用就是根據ms的配置,生成一個相對應的StatementHandler對象
    // 并設置到持有的delegate屬性中,本對象的所有方法都是通過調用delegate的相應方法實現的     
    switch (ms.getStatementType()) {
            case STATEMENT:
              delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
              break;
            case PREPARED:
              delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
              break;
            case CALLABLE:
              delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
              break;
            default:
              throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
          }
  }

BaseStaementHandler看它以 Base 開頭,就可以猜到 它是一個實現了 StatementHandler 接口的抽象類,這個類只提供了一些參數綁定相關的方法,并沒有實現操作數據庫的方法。

BaseStatementHandler 主要實現了 StatementHandler 接口中的 prepare()方法,BaseStatementHandler 依賴兩個重要的組件,ParameterHandler 和 ResultSetHandler。

3.ParameterHandler

DefaultParameterHandler默認實現

我們要執行的 SQL 語句中可能包含占位符"?",而每個"?"都對應了 BoundSql 中 parameterMappings 集合中的一個元素,在該 ParameterMapping 對象中記錄了對應的參數名稱以及該參數的相關屬性。ParameterHandler 接口定義了一個非常重要的方法 setParameters(),該方法主要負責調用 PreparedStatement 的 set*()系列方法,為 SQL 語句綁定實參。MyBatis 只為 ParameterHandler 接口提供了唯一一個實現類 DefaultParameterHandler。

4.ResultSetHandler

SqlSession

 

MyBatis源碼解析

 

DefaultSqlSession 是單獨使用 MyBatis 進行開發時,最常用的 SqISession 接口實現。其實現了 SqISession 接口中定義的方法,及各方法的重載。select()系列方法、selectOne()系列方法、selectList()系列方法、selectMap()系列方法之間的調用,殊途同歸,它們最終都會調用 Executor 的 query()方法。

上述重載方法最終都是通過調用 Executor 的 query(MappedStatement, Object, RowBounds,ResultHandler)方法實現數據庫查詢操作的,但各自對結果對象進行了相應的調整,例如:selectOne()方法是從結果對象集合中獲取了第一個元素返回;selectMap()方法會將 List 類型的結果集 轉換成 Map 類型集合返回;select()方法是將結果集交由用戶指定的 ResultHandler 對象處理,且沒有返回值;selectList()方法則是直接返回結果對象集合。 DefaultSqlSession 的 insert()方法、update()方法、delete()方法也有多個重載,它們最后都是通過調用 DefaultSqlSession 的 update(String, Object)方法實現的,該重載首先會將 dirty 字段置為 true,然后再通過 Executor 的 update()方法完成數據庫修改操作。 DefaultSqlSession 的 commit()方法、rollback()方法以及 close()方法都會調用 Executor 中相應的方法,其中就會涉及清空緩存的操作,之后就會將 dirty 字段設置為 false。 上述的 dirty 字段主要在
isCommitOrRollbackRequired()方法中,與 autoCommit 字段以及用戶傳入的 force 參數共同決定是否提交/回滾事務。該方法的返回值將作為 Executor 的 commit()方法和 rollback()方法的參數。


SqlSessionFactory 負責創建 SqlSession 對象,其中包含了多個 openSession()方法的重載,可以通過其參數指定事務的隔離級別、底層使用 Executor 的類型、以及是否自動提交事務等方面的配置。

DefaultSqlSessionFactory 是 SqlSessionFactory 接口的默認實現,主要提供了兩種創建 DefaultSqlSession 對象的方式,一種方式是通過數據源獲取數據庫連接,并創建 Executor 對象以及 DefaultSqlSession 對象;另一種方式是用戶提供數據庫連接對象,DefaultSqlSessionFactory 根據該數據庫連接對象獲取 autoCommit 屬性,創建 Executor 對象以及 DefaultSqlSession 對象。

SqlSessionManager 同時實現了 SqlSession 接口和 SqlSessionFactory 接口,所以同時提供了 SqlSessionFactory 創建 SqlSession 對象,以及 SqlSession 操縱數據庫的功能。

SqlSessionManager 與 DefaultSqlSessionFactory 的主要不同點 SqlSessionManager 提供了兩種模式,第一種模式與 DefaultSqlSessionFactory 的行為相同,同一線程每次通過 SqlSessionManager 對象訪問數據庫時,都會創建新的 SqlSession 對象完成數據庫操作。第二種模式是 SqlSessionManager 通過 localSqlSession 這 ThreadLocal 變量,記錄與當前線程綁定的 SqlSession 對象,供當前線程循環使用,從而避免在同一線程多次創建 SqlSession 對象帶來的性能損失。

DataSource

DataSourceFactory數據工廠

/**
 * 數據源工廠
 * @author Clinton Begin
 */
public interface DataSourceFactory {

    /**
     * 設置 dataSource 屬性
     * @param props
     */
    void setProperties(Properties props);

    /**
     * 獲取 dataSource
     * @return {@link DataSource}
     */
    DataSource getDataSource();

}

 

MyBatis源碼解析

 

DyanmicSqlSourcce動態sql

PooledDataSource 管理的數據庫連接對象 是由其持有的 UnpooledDataSource 對象 創建的,并由 PoolState 管理所有連接的狀態。 PooledDataSource 的 getConnection()方法 會首先調用 popConnection()方法 獲取 PooledConnection 對象,然后通過 PooledConnection 的 getProxyConnection()方法 獲取數據庫連接的代理對象。popConnection()方法 是 PooledDataSource 的核心邏

MapperMethod 中封裝了 Mapper 接口 中對應方法的信息,和對應 sql 語句 的信息,是連接 Mapper 接口 及映射配置文件中定義的 sql 語句 的橋梁。

MapperMethod 中持有兩個非常重要的屬性,這兩個屬性對應的類 都是 MapperMethod 中的靜態內部類。另外,MapperMethod 在被實例化時就對這兩個屬性進行了初始化
MapperMethod 中的核心方法 execute() 就主要用到了這兩個類

  public static class SqlCommand {

    // sql語句的id
    private final String name;
    // sql語句的類型,SqlCommandType 是枚舉類型,持有常用的 增、刪、改、查等操作類型
    private final SqlCommandType type;
    
  }

 

MyBatis源碼解析

 

 MyBatis 和spring整合源碼

spring啟動時候需要是由一個bean.xml配置

ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");

bean.xml配置例如:


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 加載數據源 -->
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath*:mappers/*Mapper.xml"/>
</bean>
 
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 指定掃描的包,如果存在多個包使用(逗號,)分割 -->
    <property name="basePackage" value="com.test.bean"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

MapperScannerConfigurer

這個類主要的方法就是
postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法

MyBatis源碼解析

 

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  if (this.processPropertyPlaceHolders) {
    processPropertyPlaceHolders();
  }
//ClassPathMapperScanner掃描器,這個掃描器繼承了spring的ClassPathBeanDefinitionScanner。
  /**
第一掃描basePackage包下面所有的class類
第二將所有的class類封裝成為spring的ScannedGenericBeanDefinition sbd對象
第三過濾sbd對象,只接受接口類
第四完成sbd對象屬性的設置,比如設置sqlSessionFactory、BeanClass等,這個sqlSessionFactory是本文接下來要解析的SqlSessionFactoryBean
第五將過濾出來的sbd對象通過這個BeanDefinitionRegistry registry注冊器注冊到DefaultListableBeanFactory中,這個registry就是方法postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)中的參數。

  */
  ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  scanner.setAddToConfig(this.addToConfig);
  scanner.setAnnotationClass(this.annotationClass);
  scanner.setMarkerInterface(this.markerInterface);
  scanner.setSqlSessionFactory(this.sqlSessionFactory);
  scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
  scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
  scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
  scanner.setResourceLoader(this.applicationContext);
  scanner.setBeanNameGenerator(this.nameGenerator);
  scanner.registerFilters();
  scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

以上就是實例化MapperScannerConfigurer類的主要工作,總結起來就是掃描basePackage包下所有的mapper接口類,并將mapper接口類封裝成為BeanDefinition對象,注冊到spring的BeanFactory容器中。以下時序圖不代表實際過程。

MyBatis源碼解析

 

SqlSessionFactoryBean

MyBatis源碼解析

 

分享到:
標簽:MyBatis
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定