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