摘要:內(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大致定義如下:
-- ---------------------------- -- Table structure for process -- ---------------------------- DROP TABLE IF EXISTS `process`; CREATE TABLE `process` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `status` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
對(duì)應(yīng)實(shí)體類Process,大致定義如下:
public class Process{ private int id; private String name; private ProcessStatus status; // 省略 getter setter toString 等 }
其中,枚舉類ProcessStatus,大致定義如下:
public enum ProcessStatus { RUNNING(100, "running"), BLOCKED(101, "blocked"), STOPPED(102, "stopped"); private int code; private String desc; ProcessStatus(int code, String desc) { this.code = code; this.desc = desc; } // ... }
如果此時(shí)我們想在存儲(chǔ)Process類時(shí)直接將ProcessStatus對(duì)應(yīng)成某種值,或者在查詢時(shí)直接將數(shù)據(jù)庫(kù)status字段值對(duì)應(yīng)成為ProcessStatus類,而不需要用硬編碼的方式做更多的轉(zhuǎn)換,我們可以考慮采用 MyBatis 提供的typeHandler。
MyBatis 內(nèi)置的枚舉處理器為了處理上述遇到的問(wèn)題,MyBatis 內(nèi)置了兩種 typeHandler,分別是org.apache.ibatis.type.EnumTypeHandler和org.apache.ibatis.type.EnumOrdinalTypeHandler。
EnumTypeHandler作為默認(rèn)的枚舉 typeHandler,EnumTypeHandler將使用枚舉實(shí)例名稱來(lái)和對(duì)應(yīng)的枚舉類之間做轉(zhuǎn)換。
比如process表有記錄:
id | name | status |
---|---|---|
1 | first | RUNNING |
在查詢時(shí),Process類變量status將自動(dòng)賦值為ProcessStatus.RUNNING,添加記錄時(shí)同理,數(shù)據(jù)庫(kù)值將存儲(chǔ)為其枚舉類實(shí)例名稱(RUNNING/BLOCKED/STOPPED)。
EnumOrdinalTypeHandlerEnumOrdinalTypeHandler將使用枚舉實(shí)例的 ordinal 值(序數(shù)值,從0開(kāi)始)來(lái)和枚舉類之間做轉(zhuǎn)換。
比如process有記錄:
id | name | status |
---|---|---|
1 | first | 1 |
顯式為ProcessStatus全局指定 typeHandler:
在查詢時(shí),Process類變量status將自動(dòng)賦值為ProcessStatus.BLOCKED,添加記錄時(shí)同理,數(shù)據(jù)庫(kù)值將存儲(chǔ)為其枚舉類實(shí)例序號(hào)(0/1/2)。
混合使用假如想在一處使用EnumTypeHandler,另外一處使用EnumOrdinalTypeHandler,可以在 mapped statement 中多帶帶指定 typeHandler。
insert into process (id, name, status) values (#{id}, #{name}, #{status, typeHandler=org.apache.ibatis.type.EnumTypeHandler})
或
自定義枚舉處理器
回到我們的場(chǎng)景描述中來(lái),我們需要用枚舉實(shí)例的 code 值來(lái)對(duì)應(yīng)相應(yīng)的枚舉。此時(shí),系統(tǒng)內(nèi)置的兩個(gè)枚舉處理器便不能很好地完成我們的需求了,所以我們要自定義枚舉處理器。
實(shí)現(xiàn)方法枚舉處理器也是處理器(typeHandler)的一種,關(guān)于自定義處理器的內(nèi)容,可以參考官方文檔。主要操作便是實(shí)現(xiàn)org.apache.ibatis.type.TypeHandler或繼承更為方便的org.apache.ibatis.type.BaseTypeHandler類。
我們選擇繼承BaseTypeHandler來(lái)完成工作,BaseTypeHandler需要實(shí)現(xiàn)4個(gè)方法:
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException
用于定義設(shè)置參數(shù)時(shí),該如何把 Java 類型的參數(shù)轉(zhuǎn)換為對(duì)應(yīng)的數(shù)據(jù)庫(kù)類型
public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException
用于定義通過(guò)字段名稱獲取字段數(shù)據(jù)時(shí),如何把數(shù)據(jù)庫(kù)類型轉(zhuǎn)換為對(duì)應(yīng)的 Java 類型
public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException
用于定義通過(guò)字段索引獲取字段數(shù)據(jù)時(shí),如何把數(shù)據(jù)庫(kù)類型轉(zhuǎn)換為對(duì)應(yīng)的 Java 類型
public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException
用定義調(diào)用存儲(chǔ)過(guò)程后,如何把數(shù)據(jù)庫(kù)類型轉(zhuǎn)換為對(duì)應(yīng)的 Java 類型
由于「枚舉」是一個(gè)統(tǒng)稱,不像具體類型的處理器一樣可以使用多種方式來(lái)指定匹配的 Java 類型,所以按照官方文檔的做法,我們將使用指定泛型的方式來(lái)自定義枚舉構(gòu)造器(EnumTypeHanlder和EnumOrdinalTypeHandler源代碼也是這么實(shí)現(xiàn)的),官方文檔示例:
//GenericTypeHandler.java public class GenericTypeHandler實(shí)現(xiàn)過(guò)程extends BaseTypeHandler { private Class type; public GenericTypeHandler(Class type) { if (type == null) throw new IllegalArgumentException("Type argument cannot be null"); this.type = type; } ... }
為了更好完成自定義枚舉的工作,我們修改一下我們上面定義的枚舉ProcessStatus,使它實(shí)現(xiàn)一個(gè)通用接口。
public interface BaseEnum { int getCode(); } public enum ProcessStatus implements BaseEnum{ RUNNING(100, "running"), BLOCKED(101, "blocked"), STOPPED(102, "stopped"); private int code; private String desc; ProcessStatus(int code, String desc) { this.code = code; this.desc = desc; } @Override public int getCode() { return code; } public String getDesc() { return desc; } }
然后再使用一個(gè)枚舉工作類來(lái)完成從枚舉 code 值獲得枚舉實(shí)例的工作:
public class EnumUtils { public static& BaseEnum> T codeOf(Class enumClass, int code) { T[] enumConstants = enumClass.getEnumConstants(); for (T t : enumConstants) { if (t.getCode() == code) { return t; } } return null; } }
萬(wàn)事俱備,接下來(lái)完成自定義枚舉處理器:
import com.foo.BaseEnum; import com.foo.EnumUtils; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class EnumCodeTypeHandler& BaseEnum> extends BaseTypeHandler { private final Class type; public EnumCodeTypeHandler(Class type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.type = type; } @Override public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter.getCode()); } @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { int code = rs.getInt(columnName); return rs.wasNull() ? null : EnumUtils.codeOf(this.type, code); } @Override public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { int code = rs.getInt(columnIndex); return rs.wasNull() ? null : EnumUtils.codeOf(this.type, code); } @Override public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { int code = cs.getInt(columnIndex); return cs.wasNull() ? null : EnumUtils.codeOf(this.type, code); } }
在 mybatis-config.xml 中注冊(cè)枚舉處理器
假設(shè)數(shù)據(jù)庫(kù)process表有如下記錄:
id | name | status |
---|---|---|
1 | first | 101 |
ProcessMapper.java使用如下查詢:
@Select("select * from process where id=#{id}") public Process findById(int id);
查詢結(jié)果 status 值將會(huì)對(duì)應(yīng)到枚舉實(shí)例 ProcessStatus.BLOCKED上。
查詢結(jié)果Process{id=1, name="first", status=BLOCKED}
設(shè)置默認(rèn)枚舉處理器在 mybatis-config.xml 中為單個(gè)枚舉注冊(cè)枚舉處理器的方式在需要處理的枚舉數(shù)量增長(zhǎng)時(shí),會(huì)帶來(lái)很多不必要的工作量,根據(jù)官方文檔,我們可以在 configuration - settings節(jié)點(diǎn)下設(shè)置默認(rèn)枚舉處理器,沒(méi)有特殊指定處理器的枚舉都將默認(rèn)使用這個(gè)處理器。
說(shuō)明和參考資料
說(shuō)明:文中代碼測(cè)試基于 JDK 8,MyBatis 3.4.5。
參考資料:
MyBatis官方文檔之Configuration
如何在MyBatis中優(yōu)雅的使用枚舉,特別感謝這篇清晰明了的文章。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71158.html
摘要:自帶對(duì)枚舉的處理類該類實(shí)現(xiàn)了枚舉類型和類型的相互轉(zhuǎn)換。而在具體中也需要使用屬性,如在處理到該位置時(shí),就會(huì)調(diào)用指定的處理類來(lái)處理枚舉類型。 mybatis自帶對(duì)枚舉的處理類 org.apache.ibatis.type.EnumOrdinalTypeHandler :該類實(shí)現(xiàn)了枚舉類型和Integer類型的相互轉(zhuǎn)換。 但是給轉(zhuǎn)換僅僅是將對(duì)應(yīng)的枚舉轉(zhuǎn)換為其索引位置,也就是ordinal(...
摘要:本文速覽本篇文章是我為接下來(lái)的源碼分析系列文章寫(xiě)的一個(gè)導(dǎo)讀文章。年該項(xiàng)目從基金會(huì)遷出,并改名為。同期,停止維護(hù)。符號(hào)所在的行則是表示的執(zhí)行結(jié)果。同時(shí),使用無(wú)需處理受檢異常,比如。另外,把寫(xiě)在配置文件中,進(jìn)行集中管理,利于維護(hù)。 1.本文速覽 本篇文章是我為接下來(lái)的 MyBatis 源碼分析系列文章寫(xiě)的一個(gè)導(dǎo)讀文章。本篇文章從 MyBatis 是什么(what),為什么要使用(why),...
摘要:枚舉類型提供了提供了持久化的枚舉類型。假設(shè)表結(jié)構(gòu)的列,使用類型存儲(chǔ)或,對(duì)象使用枚舉類型標(biāo)識(shí)當(dāng)執(zhí)行語(yǔ)句時(shí),或會(huì)存儲(chǔ)到列,如果想要存儲(chǔ)的時(shí)枚舉值而不是枚舉名字,就需要配置類型處理器和提供了對(duì)和的內(nèi)檢支持,將映射為,將映射為數(shù)組。 mybatis中靜態(tài)sql語(yǔ)句有時(shí)不足以滿足用戶的需求,因此其提供了動(dòng)態(tài)sql標(biāo)簽。 IF標(biāo)簽 if標(biāo)簽通過(guò)條件測(cè)試,動(dòng)態(tài)插入sql片段,例如: an...
摘要:學(xué)習(xí)筆記有官方的中文開(kāi)發(fā)文檔并且針對(duì)使用者比較友好是一款優(yōu)秀的持久層框架,它支持定制化存儲(chǔ)過(guò)程以及高級(jí)映射。它只和配置有關(guān),存在的意義僅在于用來(lái)減少類完全限定名的冗余,為了簡(jiǎn)化中的書(shū)寫(xiě)。 Mybatis學(xué)習(xí)筆記 mybatis有官方的中文開(kāi)發(fā)文檔并且針對(duì)使用者比較友好:http://www.mybatis.org/mybatis-3/zh/ MyBatis 是一款優(yōu)秀的持久層框架,它支...
摘要:的簡(jiǎn)稱,運(yùn)行環(huán)境,為的運(yùn)行提供了所需環(huán)境。分割字符串,返回一個(gè)分割后的字符串?dāng)?shù)組。線程安全是線程安全的,而是非線程安全的。迭代器取代了集合框架中的,迭代器允許調(diào)用者在迭代過(guò)程中移除元素。 本文分為十九個(gè)模塊,分別是:?Java 基礎(chǔ)、容器、多線程、反射、對(duì)象拷貝、Java Web 、異常、網(wǎng)絡(luò)、設(shè)計(jì)模式、Spring/Spring MVC、Spring Boot/Spring Clou...
閱讀 3295·2021-11-25 09:43
閱讀 2097·2021-09-22 10:02
閱讀 3357·2021-09-06 15:00
閱讀 2308·2019-08-30 15:56
閱讀 2361·2019-08-30 15:54
閱讀 3238·2019-08-30 14:14
閱讀 2271·2019-08-29 17:25
閱讀 2914·2019-08-29 17:16