摘要:無論是在預處理語句中設置一個參數時,還是從結果集中取出一個值時,都會用類型處理器將獲取的值以合適的方式轉換成類型。這個抽象類實現了接口,這個接口主要定義了類型轉換的幾種操作。至于這個抽象類繼承的,主要是提供了獲取這個具體是哪個類型。
TypeHandlers
無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,還是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。
下面是常見的一些對應類型:
以BigDecimalTypeHandler看一下,它主要完成了哪些工作。
這個類的第一個方法是對預處理語句(PreparedStatement)設置參數,之后的三個函數都是從ResultSet或者用于執行存儲過程的CallableStatement語句中獲取BigDecimal類型的數值,用于向BigDecimal類型的Java字段賦值。
BigDecimalTypeHandler繼承的BaseTypeHandler是個泛型類,其他的TypeHandler也是通過繼承這個抽象類,實現其中的抽象方法,實現類型轉換的工作。
這個抽象類實現了TypeHandler接口,這個接口主要定義了類型轉換的幾種操作。
至于這個抽象類繼承的TypeReference
大致介紹了TypeHandler的作用,及其相關類,我們來看看如何使用它。
今天遇到的主要是從SqlServer中取數據,遇到很多列都是Numeric(10,2)類型,指的是字段是數字型,長度為10,小數為兩位。Mybatis默認的BigDecimalTypeHandler取到后,都默認變成4位小數,不夠的補了0。而上層的要求是,拿到的和數字相關的數據都要2位小數。
有兩種做法,一種是在所有給上層賦值的時候,都人工對BigDeciam的數據做如下操作。
setScale(2, BigDecimal.ROUND_HALF_UP)
因為這是一個全局性的要求,所有相關的地方,都需要有這個代碼,雖然可以寫一個工具類,各個地方調用,但就對原本間接的代碼造成了侵入。既然這樣,為什么不試試TypeHandler。
我的做法是繼承BigDecimalTypeHandler,覆蓋原來的取值方法,對取到的數值做范圍限定。
加上@MappedJdbcTypes注解是為了表明這個類是用于映射JdbcType的NUMERIC類型,這會覆蓋默認的用于轉換Java BegDecimal和Jdbc NUMERIC的BigDecimal,在后面源碼中可略窺一二。
開發完這個轉換類后,你需要在Mybatis的配置文件中聲明這個TypeHandler,這樣Mybatis才知道你自己聲明了一個TypeHandler。
這樣TypeHandler就起作用了。下面是前后效果。
首先Mybatis有一個默認的TypeHandler實現,這些TypeHandler是如何被Mybatis識別的呢。
答案是TypeHandlerRegistry。在Mybatis初始化配置的時候,TypeHandlerRegistry會把JdbcType和Java類型對應的映射關系注冊進該類內部的Map中。
JDBC_TYPE_HANDLER_MAP中記錄的是JdbcType和TypeHandler對應的關系。
TYPE_HANDLER_MAP中記錄的是Java類型和對應的所有JdbcType以及其對應TypeHandler的映射關系關系。
UNKNOWN_TYPE_HANDLER是在執行BaseTypeHandler的抽象方法時,去先解析出來該用什么TypeHandler,目前還沒用到,先不研究。
ALL_TYPE_HANDLERS_MAP中記錄的是所有TypeHandler的Class和其實例之間的映射關系。
我們以系統默認注冊的三個作為例子,看看整個執行的流程
1 register(String.class, new StringTypeHandler()); 2 register(String.class, JdbcType.NCHAR, new NStringTypeHandler()); 3 register(JdbcType.NCHAR, new NStringTypeHandler());
第一個是告訴 String類型的轉換,要用StringTypeHandler。
直接進的這個函數,因為我們的TypeHandler上并沒有打注解,因此直接進入箭頭標記的邏輯。
然后繼續注冊,只不過jdbcType是null。
后續的代碼比較簡單,會先從Type_HANLER_MAP中看是否有已經存在的 Map
第二個,傳入了jdbcType是NCHAR,和第一個類似,但直接就進入了最后一步的注冊環節,沒有去判斷傳入什么樣的jdbcType類型,因為已經指定了。
第三個是綁定了 jdbcType和Handler之間的對應關系。
OK,前面是系統默認注冊進去的,那我們看一下我們在如何使用章節中添加進去的SubBigDecimalTypeHandler是如何被注冊進去的呢。
Mybatis在應用中啟動時,會根據XML文件初始化配置,負責解析XML生成配置類的就是XMLConfigBuilder,通過調用其中的parseConfiguration方法填充配置類。
箭頭表示處,就是解析typehandlers節點,我們看看他具體做了些什么。
因為我們不是對整個package進行注冊,所以進入else分支,因為只表明了一個最簡單的Handler,所以要獲取的字段都為null,由此我們也可以看出,在編寫XML時,我們也是可以直接指定映射關系的,因為獲取不到javaType和jdbcType,后面應該是會根據這個類再解析一波。跟注冊相關的又回到了TypeHandlerRegistry這個類里面,職責還是很清晰的。
在這個方法里面,首先會獲取有沒有打MappedType這個注解,這個注解是表明這個類對應處理的JavaType是啥。我們這邊沒有找到,因此繼續往下走。
從Mybatis3.1.0開始,會自動解析這個類對應的Java類型,還記得之前我們繼承的BigDecimalTypeHandler中我們的基類BaseTypeHandler繼承了TypeReference么?
這個類的構造函數會獲取泛型中具體的類型是什么,細節代碼可以私下看一下。
獲取到了具體的Java類型,我們就繼續往下傳。
因為我們的subBigDecimalTypeHandler是打了MappedJdbcType注解的,因此之后的步驟和register(String.class, JdbcType.NCHAR, new NStringTypeHandler())是一致的,可以回看上文。
到這里,TypeHandler的注冊部分已經完成了。
在之前的關于映射的文章中,我們提過,Mybatis完成映射后,會選擇合適的TypeHandler處理器,完成對Java業務對象的賦值,我們首先找到入口在哪里。
完成賦值的就是在1,2處,我們這邊用的是自動映射,因此進1看看,具體關于TypeHandler的處理,不會有太大的差異。
在之前的createAutomaticMappings,找到列名后,會找出對應的字段,首先會判斷是否有對應的TypeHandler。
因為你知道了JDBC的類型,也通過反射知道了Java的類型。
這邊就首先去TYPE_HANDLER_MAP中找已經存在的JDBC-TypeHandler的映射,如果有的話直接取,沒有的話,就默認取null所對應的那個類型。
因為我們知道jdbc的類型是NUMERIC,而且之前注冊的SubBigDecimalTypeHandler對應的JDBC類型是NUMERIC。
因此就取了更匹配的SubBigDecimalTypeHandler。
之后就是調用getResult方法,完成值的獲取即可。
本文主要介紹了
什么是TypeHandler。
如何使用TypeHandler。
從系統默認的以及自定義的TypeHandler的注冊和獲取的角度,從源碼層面分析了整個過程。
希望得到您的點贊,打賞支持,謝謝。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70141.html
摘要:原因就是傳入的和原有的單引號,正好組成了,而后面恒等于,所以等于對這個庫執行了查所有的操作。類比的執行流程和原有的我們使用的方法就是。可以理解為就是用來解析定制的符號的語句。后續的流程,就和正常的流程一致了。 前言 在JDBC中,主要使用的是兩種語句,一種是支持參數化和預編譯的PrepareStatement,能夠支持原生的Sql,也支持設置占位符的方式,參數化輸入的參數,防止Sql注...
摘要:模板方法模式定義了一個算法的步驟,并允許子類別為一個或多個步驟提供其實踐方式。在軟件工程中,它是一種軟件設計模式,和模板沒有關連。模板方法充分運用了多態與繼承。去建設銀行支付去招商銀行支付實現模板方法的細節,我們來看使用邏輯。 Photo by Tomá? Malík on Unsplash 什么是模板方法模式?摘錄 wiki 的介紹。 模板方法模式定義了一個算法的步驟,并允許子類別為...
摘要:內置的枚舉處理器為了處理上述遇到的問題,內置了兩種,分別是和。將使用枚舉實例的值序數值,從開始來和枚舉類之間做轉換。比如有記錄顯式為全局指定在查詢時,類變量將自動賦值為,添加記錄時同理,數據庫值將存儲為其枚舉類實例序號。 場景描述 我們在實際場景中經常會遇到需要將枚舉值存儲到數據庫中,或是將從數據庫中查詢到的值對應到枚舉類上的情況。 比如表process大致定義如下: -- -----...
摘要:主要有三種方案駝峰式命名開關,或者不開,數據庫列和字段名全一致。開啟開配置項后,在匹配時,能夠根據數據庫列名找到對應對應的駝峰式命名后的字段。經過若干次中途崩潰,我終于寫完了駝峰式命名開關下,我們是如何完成數據庫列和字段名的映射的。 在上篇博客-[[JDBC] 處理ResultSet,構建Java對象](https://my.oschina.net/kailun...中提到,我們需要分...
閱讀 1572·2021-10-25 09:44
閱讀 2937·2021-09-04 16:48
閱讀 1564·2019-08-30 15:44
閱讀 2509·2019-08-30 15:44
閱讀 1738·2019-08-30 15:44
閱讀 2825·2019-08-30 14:14
閱讀 2977·2019-08-30 13:00
閱讀 2152·2019-08-30 11:09