MyBatis遊玩

筆記學習自MyBatis技術內幕,做者的水平很高,雖然書裏表面說的MyBatis源碼,但其實是談論設計模式的具體應用,強推!java

基礎支持

類型轉換

Java類型到Jdbc類型是怎麼實現的?sql

MyBatis的類型轉換器依賴於TypeHandler接口,其中getResult負責將Java類型轉換成JdbcType類型,而setParameter則反之編程

內置的抽象類類爲BaseTypeHandler,全部默認實現類都繼承於它,基本是調用PreparedStatementResultSet方法來具體實現參數綁定/獲取指定列值設計模式

TypeHandlerRegistry負責管理MyBatis初始化階段建立的全部已知TypeHandler對象api

具體的是提供映射(真·Map對象),核心字段有數組

JDBC_TYPE_HANDLER_MAP:用於表示JdbcTypeTypeHandler的惟一映射緩存

TYPE_HANDLER_MAP:用於表示Type到多個JdbcTypeTypeHandler的映射(好比String會對應於char和varchar)session

好比類型爲Map<JdbcType,TypeHandler<?>>JDBC_TYPE_HANDLER_MAP字段(實質爲EnumMap),當從結果集獲取數據時,依靠這個還實現Jdbc類型到Java類型的轉換mybatis

而關鍵的register的常見重載方法有(Type,JdbcType,TypeHandler)的入參,具體註冊順序爲app

1.檢測javaType是否爲空,不管是否爲空均加入到ALL_TYPE_HANDLERS_MAP(key爲handler.getClass())

2.若是非空,從TYPE_HANDLER_MAP中經過javaType得到對應的Handler的Map

3.若是沒有對應Handler的Map,則經過直接新建一個空的HashMap並加入到TYPE_HANDLER_MAP

4.在對應的handler的Map加入(jdbcType,handler)鍵值對

這樣實現了單個javaType對應多個jdbcType的handler映射註冊,在此以後要得到typeHandler可經過getTypeHandler(type,jdbcType)獲得,其實就是跑上面的Map的對應鍵值便可

類型別名的實現?

MyBatis經過TypeAliasRegistry完成表/列名的別名註冊和管理

具體是經過Map<String,Class<?>> TYPE_ALIASES字段以及registerAlias()實現,就是個get檢查有沒有而後再put進去的過程(衝突會拋出異常!)。。

日誌

MyBatis經過適配器模式實現對不一樣的日誌接口/實現(Adaptee)的兼容,其內部使用接口爲Log(適配器中的Target),由LogFactory來實現適配過程(Adapter)

資源加載

MyBatis封裝了ClassLoaderWrapper做爲ClassLoader的包裝器,使用起來和ClassLoader一致,但可調整ClassLoader使用順序(多個ClassLoader依次檢查,並從中挑出可用的)

該類中有兩個字段defaultClassLoadersystemClassLoader,前者由系統指定,後者由ClassLoader.getSystemClassLoader()提供

該ClassLoaderWrapper中的getClassLoaders(classLoader)返回ClassLoader[]數組,分別是

classLoader / defaultClassLoader / Thread.currentThread().getContextClassLoader() / getClass().getClassLoader() / systemClassLoader

不一樣的類加載器具備不一樣的訪問權限,對於獲取資源如URL getResourceAsURL(resource,classLoader[])就會依據上面給出的類加載器順序依次獲取資源(失敗後會再經過"/"+resource再次嘗試)

DataSource

數據源組件須要經過實現javax.sql.DataSource接口來實現,MyBatis經過經典的工廠模式來提供兩個實現類PooledDataSourceUnpooledDataSource,其對應的工廠類爲實現DataSourceFactoryPooledDataSourceFactoryUnpooledDataSourceFactory,其工廠接口(關注建立API)-工廠實現(關注建立邏輯)-產品接口(關注用戶API)-產品實現(關注業務邏輯)的設計典範是十分規範的面向接口編程

在實現類中均封裝好的註冊JDBC驅動、創建Connection等模板

PooledDataSource不直接管理javax.sql.Connection對象,而是委託給PooledConnection,它直接封裝了Connection對象及其代理(比方說當調用代理的close()時實際是調用PooledDataSource.pushConnection()

而且由PooledState經過ArrayList<PooledConnection>管理idle的鏈接

事務管理

彷佛沒啥好說的?也是個工廠實現

緩存

Cache接口提供很是多的緩存實現裝飾器,好比SoftCacheLruCacheSynchronizedCache

Cache中指定的key CacheKey不是一個簡單的String,內部封裝了multiplier/hashCode/checkSum/count等用於重寫hashCode()equals()的字段,還有List<Object> updateList會記錄多種影響緩存項的因素(既可經過多個對象組成一個key),好比MappedStatement的id/查詢結果集的範圍/查詢使用的SQL/傳遞到SQL的參數,每次update(obj)到一個key時會判斷是不是數組,若是是則添加多個內部對象到cacheKey,無論如何都是經過doUpdate(obj)來具體更新,四個字段更新:count++,checkSum+=baseHashcode,baseHashCode*=count,hashCode=multiplier*hashCode+baseHashCode,最後把obj放入到updateList中,判斷key是否相等則依次按照上述字段進行對比,無可奈何才用updateList的元素比較

Binding

Binding實現xml/註解到接口的綁定(就是一堆Mapper就能實現執行SQL的原理)

從而實現SQL到Java層的對接

XxxMapper mapper = session.getMapper(XxxMapper.class);

Xxx obj = mapper.do(...);

POJO到mapper的實現?

就是個面向接口的動態代理,所以寫mapper時聲明interface

解析器

解析器指對XML的處理,MyBatis使用DOM解析方式,具體使用到XPath解析並將其封裝到XPathParser

反射模塊

MyBatis提供封裝好的reflection

核心處理

配置解析

MyBatis初始化工做爲加載並解析mybatis-config.xml配置文件、映射配置文件和相關的註解

其初始化入口爲SqlSessionFactoryBuilder.build(reader,enviroonment,properties)

具體的會先嚐試建立XMLConfigBuilder parser,若是成功則委託給build(parser.parse())

XMLConfigBuilder就是一個BaseBuilder抽象類的具體實現

BaseBuilder包含一個全局惟一配置configuration,別名標記typeAliasRegistry,handler註冊中心typeHandlerRegistry,後面兩個在前面已經討論過細節

外部API流程

1.經過配置文件生成SqlSessionFactory對象,SqlSessionFactory生成SqlSession(openSession())

2.SqlSession接口定義執行SQL所需的方法

3.經過SqlSession對象執行配置中的SQL語句

4.經過SqlSession對象提交事務

5.關閉SqlSession

相關文章
相關標籤/搜索