摘要:內置的枚舉處理器為了處理上述遇到的問題,內置了兩種,分別是和。將使用枚舉實例的值序數值,從開始來和枚舉類之間做轉換。比如有記錄顯式為全局指定在查詢時,類變量將自動賦值為,添加記錄時同理,數據庫值將存儲為其枚舉類實例序號。
場景描述
我們在實際場景中經常會遇到需要將枚舉值存儲到數據庫中,或是將從數據庫中查詢到的值對應到枚舉類上的情況。
比如表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;
對應實體類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; } // ... }
如果此時我們想在存儲Process類時直接將ProcessStatus對應成某種值,或者在查詢時直接將數據庫status字段值對應成為ProcessStatus類,而不需要用硬編碼的方式做更多的轉換,我們可以考慮采用 MyBatis 提供的typeHandler。
MyBatis 內置的枚舉處理器為了處理上述遇到的問題,MyBatis 內置了兩種 typeHandler,分別是org.apache.ibatis.type.EnumTypeHandler和org.apache.ibatis.type.EnumOrdinalTypeHandler。
EnumTypeHandler作為默認的枚舉 typeHandler,EnumTypeHandler將使用枚舉實例名稱來和對應的枚舉類之間做轉換。
比如process表有記錄:
id | name | status |
---|---|---|
1 | first | RUNNING |
在查詢時,Process類變量status將自動賦值為ProcessStatus.RUNNING,添加記錄時同理,數據庫值將存儲為其枚舉類實例名稱(RUNNING/BLOCKED/STOPPED)。
EnumOrdinalTypeHandlerEnumOrdinalTypeHandler將使用枚舉實例的 ordinal 值(序數值,從0開始)來和枚舉類之間做轉換。
比如process有記錄:
id | name | status |
---|---|---|
1 | first | 1 |
顯式為ProcessStatus全局指定 typeHandler:
在查詢時,Process類變量status將自動賦值為ProcessStatus.BLOCKED,添加記錄時同理,數據庫值將存儲為其枚舉類實例序號(0/1/2)。
混合使用假如想在一處使用EnumTypeHandler,另外一處使用EnumOrdinalTypeHandler,可以在 mapped statement 中多帶帶指定 typeHandler。
insert into process (id, name, status) values (#{id}, #{name}, #{status, typeHandler=org.apache.ibatis.type.EnumTypeHandler})
或
自定義枚舉處理器
回到我們的場景描述中來,我們需要用枚舉實例的 code 值來對應相應的枚舉。此時,系統內置的兩個枚舉處理器便不能很好地完成我們的需求了,所以我們要自定義枚舉處理器。
實現方法枚舉處理器也是處理器(typeHandler)的一種,關于自定義處理器的內容,可以參考官方文檔。主要操作便是實現org.apache.ibatis.type.TypeHandler或繼承更為方便的org.apache.ibatis.type.BaseTypeHandler類。
我們選擇繼承BaseTypeHandler來完成工作,BaseTypeHandler需要實現4個方法:
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException
用于定義設置參數時,該如何把 Java 類型的參數轉換為對應的數據庫類型
public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException
用于定義通過字段名稱獲取字段數據時,如何把數據庫類型轉換為對應的 Java 類型
public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException
用于定義通過字段索引獲取字段數據時,如何把數據庫類型轉換為對應的 Java 類型
public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException
用定義調用存儲過程后,如何把數據庫類型轉換為對應的 Java 類型
由于「枚舉」是一個統稱,不像具體類型的處理器一樣可以使用多種方式來指定匹配的 Java 類型,所以按照官方文檔的做法,我們將使用指定泛型的方式來自定義枚舉構造器(EnumTypeHanlder和EnumOrdinalTypeHandler源代碼也是這么實現的),官方文檔示例:
//GenericTypeHandler.java public class GenericTypeHandler實現過程extends BaseTypeHandler { private Class type; public GenericTypeHandler(Class type) { if (type == null) throw new IllegalArgumentException("Type argument cannot be null"); this.type = type; } ... }
為了更好完成自定義枚舉的工作,我們修改一下我們上面定義的枚舉ProcessStatus,使它實現一個通用接口。
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; } }
然后再使用一個枚舉工作類來完成從枚舉 code 值獲得枚舉實例的工作:
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; } }
萬事俱備,接下來完成自定義枚舉處理器:
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 中注冊枚舉處理器
假設數據庫process表有如下記錄:
id | name | status |
---|---|---|
1 | first | 101 |
ProcessMapper.java使用如下查詢:
@Select("select * from process where id=#{id}") public Process findById(int id);
查詢結果 status 值將會對應到枚舉實例 ProcessStatus.BLOCKED上。
查詢結果Process{id=1, name="first", status=BLOCKED}
設置默認枚舉處理器在 mybatis-config.xml 中為單個枚舉注冊枚舉處理器的方式在需要處理的枚舉數量增長時,會帶來很多不必要的工作量,根據官方文檔,我們可以在 configuration - settings節點下設置默認枚舉處理器,沒有特殊指定處理器的枚舉都將默認使用這個處理器。
說明和參考資料
說明:文中代碼測試基于 JDK 8,MyBatis 3.4.5。
參考資料:
MyBatis官方文檔之Configuration
如何在MyBatis中優雅的使用枚舉,特別感謝這篇清晰明了的文章。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71158.html
摘要:自帶對枚舉的處理類該類實現了枚舉類型和類型的相互轉換。而在具體中也需要使用屬性,如在處理到該位置時,就會調用指定的處理類來處理枚舉類型。 mybatis自帶對枚舉的處理類 org.apache.ibatis.type.EnumOrdinalTypeHandler :該類實現了枚舉類型和Integer類型的相互轉換。 但是給轉換僅僅是將對應的枚舉轉換為其索引位置,也就是ordinal(...
摘要:本文速覽本篇文章是我為接下來的源碼分析系列文章寫的一個導讀文章。年該項目從基金會遷出,并改名為。同期,停止維護。符號所在的行則是表示的執行結果。同時,使用無需處理受檢異常,比如。另外,把寫在配置文件中,進行集中管理,利于維護。 1.本文速覽 本篇文章是我為接下來的 MyBatis 源碼分析系列文章寫的一個導讀文章。本篇文章從 MyBatis 是什么(what),為什么要使用(why),...
摘要:枚舉類型提供了提供了持久化的枚舉類型。假設表結構的列,使用類型存儲或,對象使用枚舉類型標識當執行語句時,或會存儲到列,如果想要存儲的時枚舉值而不是枚舉名字,就需要配置類型處理器和提供了對和的內檢支持,將映射為,將映射為數組。 mybatis中靜態sql語句有時不足以滿足用戶的需求,因此其提供了動態sql標簽。 IF標簽 if標簽通過條件測試,動態插入sql片段,例如: an...
摘要:學習筆記有官方的中文開發文檔并且針對使用者比較友好是一款優秀的持久層框架,它支持定制化存儲過程以及高級映射。它只和配置有關,存在的意義僅在于用來減少類完全限定名的冗余,為了簡化中的書寫。 Mybatis學習筆記 mybatis有官方的中文開發文檔并且針對使用者比較友好:http://www.mybatis.org/mybatis-3/zh/ MyBatis 是一款優秀的持久層框架,它支...
摘要:的簡稱,運行環境,為的運行提供了所需環境。分割字符串,返回一個分割后的字符串數組。線程安全是線程安全的,而是非線程安全的。迭代器取代了集合框架中的,迭代器允許調用者在迭代過程中移除元素。 本文分為十九個模塊,分別是:?Java 基礎、容器、多線程、反射、對象拷貝、Java Web 、異常、網絡、設計模式、Spring/Spring MVC、Spring Boot/Spring Clou...
閱讀 3287·2021-11-25 09:43
閱讀 2089·2021-09-22 10:02
閱讀 3338·2021-09-06 15:00
閱讀 2301·2019-08-30 15:56
閱讀 2353·2019-08-30 15:54
閱讀 3230·2019-08-30 14:14
閱讀 2263·2019-08-29 17:25
閱讀 2906·2019-08-29 17:16