无论是MyBatis在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成java类型。
可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。具体做法为:
实现org.apache.ibatis.type.TypeHandler接口,或继承一个很便利的类org.apache.ibatis.type.BaseTypeHandler,然后可选择性地将它映射到一个JDBC类型。比如:
// ExampleTypeHandler.java @MappedJdbcTypes(JdbcType.VARCHAR) public class ExampleTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } } |
<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/> </typeHandlers> |
使用这个的类型处理器将会覆盖已经存在的处理java的String类型属性和VARCHAR参数及结果的类型处理器。
要注意MyBatis不会窥探数据库元信息来决定使用哪种类型,所以必须在参数和结果映射中指明那是VARCHAR类型的字段,以使其能够绑定到正确的类型处理器上。
这是因为:MyBatis直到语句被执行才清楚数据类型。
通过类型处理器的泛型,MyBatis可以得知该类型处理器处理的java类型,不过这种行为可以通过两种方法改变:
·在类型处理器的配置元素(typeHandler element)上增加一个javaType属性(比如:javaType=”String”);
·在类型处理器的类上(TypeHandler class)增加一个@MappedTypes注解来指定与其关联的java类型列表。如果是在javaType属性中也同时指定,则注解方式将被忽略。
可以通过两种方式来指定被关联的JDBC类型:
·在类型处理器的配置元素上增加一个jdbcType属性(比如:jdbcType=”VARCHAR”);
·在类型处理器的类上(TypeHandler class)增加一个@MappedJdbcTypes注解来指定与其关联的JDBC类型列表。如果在jdbcType属性中也同时指定,则注解方式将会被忽略。
当决定在ResultMap中使用某一TypeHandler时,此时java类型是已知的(从结果类型中获得),但是JDBC类型是未知的。
因此MyBatis使用javaType=[TheJavaType],jdbcType=null的组合来选择一个TypeHandler。
这意味着使用@MappedJdbcTypes注解可以限制TypeHandler的范围,同时除非显示的设置,否则TypeHandler在ResultMap中将是无效的。
如果希望在ResultMap中使用TypeHandler,那么设置@MappedJdbcTypes注解的includeNullJdbcType=true即可。
然而从MyBatis3.4.0开始,如果只有一个注册的TypeHandler来处理java类型,那么它将是ResultMap使用Java类型时的默认值(即使没有includeNullJdbcType=true)。
最后,可以让MyBatis为你查找类型处理器:
<!-- mybatis-config.xml --> <typeHandlers> <package name="org.mybatis.example"/> </typeHandlers> |
注意在使用自动检索(autodiscovery)功能的时候,只能通过注解方式来指定JDBC的类型。
可以创建一个能够处理多个类的泛型类型处理器。
为了使用泛型类型处理器,需要增加一个接受该类的class作为参数的构造器,这样在构造一个类型处理器的时候MyBatis就会传入一个具体的类。
//GenericTypeHandler.java public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> { private Class<E> type; public GenericTypeHandler(Class<E> type) { if (type == null) throw new IllegalArgumentException("Type argument cannot be null"); this.type = type; } ... |
EnumTypeHandler和EnumOrdinalTypeHandler都是泛型类型处理器(generic TypeHandler)
下表描述了一些默认的类型处理器:
类型处理器 |
java类型 |
JDBC类型 |
BooleanTypeHandler |
java.lang.Boolean,boolean |
数据库兼容的BOOLEAN |
ByteTypeHandler |
java.lang.Byte,byte |
数据库兼容的NUMERIC或BYTE |
ShortTypeHandler |
java.lang.Short,short |
数据库兼容的NUMERIC或SHORT INTEGER |
IntegerTypeHandler |
java.lang.Integer,int |
数据库兼容的NUMERIC或INTEGER |
LongTypeHandler |
java.lang.Long,long |
数据库兼容的NUMERIC或LONG INTEGER |
FloatTypeHandler |
java.lang.Float,float |
数据库兼容的NUMERIC或FLOAT |
DoubleTypeHandler |
java.lang.Double,double |
数据库兼容的NUMERIC或DOUBLE |
BigDecimalTypeHandler |
java.math.BigDecimal |
数据库兼容的NUMERIC或DECIMAL |
StringTypeHandler |
java.lang.String |
CHAR,VARCHAR |
ClobReaderTypeHandler |
java.io.Reader |
- |
ClobTypeHandler |
java.lang.String |
CLOB,LONGVARCHAR |
NStringTypeHandler |
java.lang.String |
NVARCHAR,NCHAR |
NClobTypeHandler |
java.lang.String |
NCLOB |
BlobInputStreamTypeHandler |
java.io.InputStream |
- |
ByteArrayTypeHandler |
byte[] |
数据库兼容的字节流类型 |
BlobTypeHandler |
byte[] |
BLOB,LONGVARBINARY |
DateTypeHandler |
java.util.Date |
TIMESTAMP |
DateOnlyTypeHandler |
java.util.Date |
DATE |
TimeOnlyTypeHandler |
java.util.Date |
TIME |
SqlTimestampTypeHandler |
java.sql.Timestamp |
TIMESTAMP |
SqlDateTypeHandler |
java.sql.Date |
DATE |
SqlTimeTypeHandler |
java.sql.Time |
TIME |
ObjectTypeHandler |
Any |
OTHER或未指定类型 |
EnumTypeHandler |
Enumeration Type |
VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引) |
EnumOrdinalTypeHandler |
Enumeration Type |
任何兼容的NUMERIC或DOUBLE类型,存储枚举的索引(而不是名称) |
InstantTypeHandler |
java.time.Instant |
TIMESTAMP |
LocalDateTimeTypeHandler |
java.time.LocalDateTime |
TIMESTAMP |
LocalDateTypeHandler |
java.time.LocalDate |
DATE |
LocalTimeTypeHandler |
java.time.LocalTime |
Time |
OffsetDateTimeTypeHandler |
java.time.OffsetDateTime |
TIMESTAMP |
OffsetTimeTypeHandler |
java.time.OffsetTime |
TIME |
ZonedDateTimeTypeHandler |
java.time.ZoneDateTime |
TIMESTAMP |
YearTypeHandler |
java.time.Year |
INTEGER |
MonthTypeHandler |
java.time.Month |
INTEGER |
YearMonthTypeHandler |
java.time.YearMonth |
VARCHAR or LONGVARCHAR |
JapaneseDateTypeHandler |
java.time.chrono.JapaneseDate |
DATE |