每当MyBatis设置PreparedStatement的参数或从ResultSet中检索值时,都会使用TypeHandler以适合Java类型的方式来检索值。下表描述了默认的TypeHandlers。
自MyBatis 3.4.5版本起,默认支持JSR-310(日期和时间API)。
Type Handler | Java Types | JDBC Types |
---|---|---|
BooleanTypeHandler | java.lang.Boolean ,?boolean | Any compatible?BOOLEAN |
ByteTypeHandler | java.lang.Byte ,?byte | Any compatible?NUMERIC ?or?BYTE |
ShortTypeHandler | java.lang.Short ,?short | Any compatible?NUMERIC ?or?SMALLINT |
IntegerTypeHandler | java.lang.Integer ,?int | Any compatible?NUMERIC ?or?INTEGER |
LongTypeHandler | java.lang.Long ,?long | Any compatible?NUMERIC ?or?BIGINT |
FloatTypeHandler | java.lang.Float ,?float | Any compatible?NUMERIC ?or?FLOAT |
DoubleTypeHandler | java.lang.Double ,?double | Any compatible?NUMERIC ?or?DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | Any compatible?NUMERIC ?or?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[] | Any compatible byte stream type |
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 , or unspecified |
EnumTypeHandler | Enumeration Type | VARCHAR ?any string compatible type, as the code is stored (not index). |
EnumOrdinalTypeHandler | Enumeration Type | Any compatible?NUMERIC ?or?DOUBLE , as the position is stored (not the code itself). |
SqlxmlTypeHandler | java.lang.String | SQLXML |
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.ZonedDateTime | TIMESTAMP |
YearTypeHandler | java.time.Year | INTEGER |
MonthTypeHandler | java.time.Month | INTEGER |
YearMonthTypeHandler | java.time.YearMonth | VARCHAR ?or?LONGVARCHAR |
JapaneseDateTypeHandler | java.time.chrono.JapaneseDate | DATE |
?您可以覆盖或创建自己的TypeHandler来处理不受支持或非标准的类型。为此,您需要实现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>
使用这样的TypeHandler会覆盖Java String属性和VARCHAR参数和结果的现有TypeHandler。请注意,MyBatis不会根据数据库元数据进行内省来确定类型,因此必须在参数和结果映射中指定它是一个VARCHAR字段,以便连接正确的TypeHandler。这是因为直到执行语句时,MyBatis才能意识到数据类型。
MyBatis会通过TypeHandler的泛型类型来确定您想要处理的Java类型,但是您可以通过以下两种方式来覆盖这种行为:
给typeHandler元素添加javaType属性,例如:javaType="String"。这将明确指定TypeHandler所要关联的Java类型。
在TypeHandler类上添加@MappedTypes注解,指定要关联的Java类型列表。如果同时指定了javaType属性,@MappedTypes注解将被忽略。
可以通过两种方式来指定关联的JDBC类型:
给typeHandler元素添加jdbcType属性,例如:jdbcType="VARCHAR"。这将明确指定与TypeHandler关联的JDBC类型。
在TypeHandler类上添加@MappedJdbcTypes注解,指定要关联的JDBC类型列表。如果同时指定了jdbcType属性,@MappedJdbcTypes注解将被忽略。
?在决定在ResultMap中使用哪个TypeHandler时,已知Java类型(来自结果类型),但未知JDBC类型。因此,MyBatis将使用组合javaType=[Java类型],jdbcType=null来选择一个TypeHandler。这意味着使用@MappedJdbcTypes注解会限制TypeHandler的范围,并且除非明确设置,否则它将无法在ResultMap中使用。为了使一个TypeHandler可以在ResultMap中使用,可以在@MappedJdbcTypes注解上设置includeNullJdbcType=true。然而,自从Mybatis 3.4.0版本开始,如果一个单独的TypeHandler被注册用于处理一个Java类型,默认情况下它将被用于使用该Java类型的ResultMaps(即使没有includeNullJdbcType=true)。
最后,您可以让MyBatis为您的TypeHandler进行搜索:
<!-- mybatis-config.xml -->
<typeHandlers>
<package name="org.mybatis.example"/>
</typeHandlers>
?请注意,当使用自动发现功能时,只能使用注解来指定JDBC类型。
您可以创建一个通用的TypeHandler,它能够处理多个类。为此,您可以添加一个构造函数,接收一个Class作为参数,MyBatis在构造TypeHandler时将传递实际的类。
//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是通用的TypeHandler。