2019独角兽企业重金招聘Python工程师标准>>>
前言:mybatis以其入门低,上手快且使用十分灵活的特点,成为广大Java后端开发非常喜爱的持久层框架。作为持久层框架首先想到的问题就是如何将用户数据存到数据库中时之间的类型映射,就是 javaType -> jdbcType或者 jdbcType -> javaType,这个过程就需要用到typeHandler。mybatis已经为我们内置了大量的typeHandler,几乎可以满足我们日常开发所需。当然我们也可以实现自定义的typeHandler来处理不支持或者非标准的数据类型。
常用场景:数据类型转换(时间日期等)、字典项入库出库、数据入库加密、出库解密。。。
-
mybatis内置typeHandler。打开TypeHandlerRegistry.java可以看到
public TypeHandlerRegistry() { this.register((Class)Boolean.class, (TypeHandler)(new BooleanTypeHandler())); this.register((Class)Boolean.TYPE, (TypeHandler)(new BooleanTypeHandler())); this.register((JdbcType)JdbcType.BOOLEAN, (TypeHandler)(new BooleanTypeHandler())); this.register((JdbcType)JdbcType.BIT, (TypeHandler)(new BooleanTypeHandler())); this.register((Class)Byte.class, (TypeHandler)(new ByteTypeHandler())); this.register((Class)Byte.TYPE, (TypeHandler)(new ByteTypeHandler())); this.register((JdbcType)JdbcType.TINYINT, (TypeHandler)(new ByteTypeHandler())); this.register((Class)Short.class, (TypeHandler)(new ShortTypeHandler())); this.register((Class)Short.TYPE, (TypeHandler)(new ShortTypeHandler())); this.register((JdbcType)JdbcType.SMALLINT, (TypeHandler)(new ShortTypeHandler())); this.register((Class)Integer.class, (TypeHandler)(new IntegerTypeHandler())); this.register((Class)Integer.TYPE, (TypeHandler)(new IntegerTypeHandler())); this.register((JdbcType)JdbcType.INTEGER, (TypeHandler)(new IntegerTypeHandler())); this.register((Class)Long.class, (TypeHandler)(new LongTypeHandler())); this.register((Class)Long.TYPE, (TypeHandler)(new LongTypeHandler())); this.register((Class)Float.class, (TypeHandler)(new FloatTypeHandler())); this.register((Class)Float.TYPE, (TypeHandler)(new FloatTypeHandler())); this.register((JdbcType)JdbcType.FLOAT, (TypeHandler)(new FloatTypeHandler())); this.register((Class)Double.class, (TypeHandler)(new DoubleTypeHandler())); this.register((Class)Double.TYPE, (TypeHandler)(new DoubleTypeHandler())); this.register((JdbcType)JdbcType.DOUBLE, (TypeHandler)(new DoubleTypeHandler())); this.register((Class)String.class, (TypeHandler)(new StringTypeHandler())); this.register((Class)String.class, JdbcType.CHAR, (TypeHandler)(new StringTypeHandler())); this.register((Class)String.class, JdbcType.CLOB, (TypeHandler)(new ClobTypeHandler())); this.register((Class)String.class, JdbcType.VARCHAR, (TypeHandler)(new StringTypeHandler())); this.register((Class)String.class, JdbcType.LONGVARCHAR, (TypeHandler)(new ClobTypeHandler())); this.register((Class)String.class, JdbcType.NVARCHAR, (TypeHandler)(new NStringTypeHandler())); this.register((Class)String.class, JdbcType.NCHAR, (TypeHandler)(new NStringTypeHandler())); this.register((Class)String.class, JdbcType.NCLOB, (TypeHandler)(new NClobTypeHandler())); this.register((JdbcType)JdbcType.CHAR, (TypeHandler)(new StringTypeHandler())); this.register((JdbcType)JdbcType.VARCHAR, (TypeHandler)(new StringTypeHandler())); this.register((JdbcType)JdbcType.CLOB, (TypeHandler)(new ClobTypeHandler())); this.register((JdbcType)JdbcType.LONGVARCHAR, (TypeHandler)(new ClobTypeHandler())); this.register((JdbcType)JdbcType.NVARCHAR, (TypeHandler)(new NStringTypeHandler())); this.register((JdbcType)JdbcType.NCHAR, (TypeHandler)(new NStringTypeHandler())); this.register((JdbcType)JdbcType.NCLOB, (TypeHandler)(new NClobTypeHandler())); this.register((Class)Object.class, JdbcType.ARRAY, (TypeHandler)(new ArrayTypeHandler())); this.register((JdbcType)JdbcType.ARRAY, (TypeHandler)(new ArrayTypeHandler())); this.register((Class)BigInteger.class, (TypeHandler)(new BigIntegerTypeHandler())); this.register((JdbcType)JdbcType.BIGINT, (TypeHandler)(new LongTypeHandler())); this.register((Class)BigDecimal.class, (TypeHandler)(new BigDecimalTypeHandler())); this.register((JdbcType)JdbcType.REAL, (TypeHandler)(new BigDecimalTypeHandler())); this.register((JdbcType)JdbcType.DECIMAL, (TypeHandler)(new BigDecimalTypeHandler())); this.register((JdbcType)JdbcType.NUMERIC, (TypeHandler)(new BigDecimalTypeHandler())); this.register((Class)Byte[].class, (TypeHandler)(new ByteObjectArrayTypeHandler())); this.register((Class)Byte[].class, JdbcType.BLOB, (TypeHandler)(new BlobByteObjectArrayTypeHandler())); this.register((Class)Byte[].class, JdbcType.LONGVARBINARY, (TypeHandler)(new BlobByteObjectArrayTypeHandler())); this.register((Class)byte[].class, (TypeHandler)(new ByteArrayTypeHandler())); this.register((Class)byte[].class, JdbcType.BLOB, (TypeHandler)(new BlobTypeHandler())); this.register((Class)byte[].class, JdbcType.LONGVARBINARY, (TypeHandler)(new BlobTypeHandler())); this.register((JdbcType)JdbcType.LONGVARBINARY, (TypeHandler)(new BlobTypeHandler())); this.register((JdbcType)JdbcType.BLOB, (TypeHandler)(new BlobTypeHandler())); this.register(Object.class, this.UNKNOWN_TYPE_HANDLER); this.register(Object.class, JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER); this.register(JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER); this.register((Class)Date.class, (TypeHandler)(new DateTypeHandler())); this.register((Class)Date.class, JdbcType.DATE, (TypeHandler)(new DateOnlyTypeHandler())); this.register((Class)Date.class, JdbcType.TIME, (TypeHandler)(new TimeOnlyTypeHandler())); this.register((JdbcType)JdbcType.TIMESTAMP, (TypeHandler)(new DateTypeHandler())); this.register((JdbcType)JdbcType.DATE, (TypeHandler)(new DateOnlyTypeHandler())); this.register((JdbcType)JdbcType.TIME, (TypeHandler)(new TimeOnlyTypeHandler())); this.register((Class)java.sql.Date.class, (TypeHandler)(new SqlDateTypeHandler())); this.register((Class)Time.class, (TypeHandler)(new SqlTimeTypeHandler())); this.register((Class)Timestamp.class, (TypeHandler)(new SqlTimestampTypeHandler())); this.register((Class)Character.class, (TypeHandler)(new CharacterTypeHandler())); this.register((Class)Character.TYPE, (TypeHandler)(new CharacterTypeHandler())); }
-
如何实现自定义的typeHandler
1. 重写内置typeHandler【不赞成】
2. 实现 org.apache.ibatis.type.TypeHandler
3. 继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler 【常用方式】
下面以第三种方式来举例说明如何自定义typeHandler
public class SimpleTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, s);
}
@Override
public String getNullableResult(ResultSet resultSet, String s) throws SQLException {
return resultSet.getString(s);
}
@Override
public String getNullableResult(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString(i);
}
@Override
public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return callableStatement.getString(i);
}
}
其中:setNonNullParameter方法是数据入库时针对指定数据类型的数据
getNullableResult-1 方法是从结果集中通过column name获取指定类型数据
getNullableResult-2 方法是从结果集中通过column index获取指定类型数据
然后需要在mybatis-config.xml中配置自己的typeHandler使其生效:
在配置typeHandler时可以同时指定javaType和jdbcType组合来限定自定义的typeHandler将要处理的数据类型,也可以在SimpleTypeHandler.java文件上使用注解方式来指定:@MappedTypes指定javaType,@MappedJdbcTypes指定jdbcType。如果注解和mybatis-config.xml同时指定,则注解方式将被忽略。
需要注意的是一旦以上配置和实现完成,SimpleTypeHandler将会作用于所有的javaType=String,jdbcType=VARCHAR的字段上,这中情况一般不是我们所希望看到的。大多数情况我们只需要在某个指定的字段上进行类型转换或者处理,这种情况下我们需要借助于ResultMap。
比如我们现在要实现一个功能,用户的身份证号在进入数据库时需要加密,出库时需要解密。刚才的SimpleTypeHandler稍加改动即可。
public class SimpleTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
s = EncryptUtils.encrypt(s);//自己的加密算法
preparedStatement.setString(i, s);
}
@Override
public String getNullableResult(ResultSet resultSet, String s) throws SQLException {
return EncryptUtils.decrypt(resultSet.getString(s));//解密算法
}
@Override
public String getNullableResult(ResultSet resultSet, int i) throws SQLException {
return EncryptUtils.decrypt(resultSet.getString(i));
}
@Override
public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return EncryptUtils.decrypt(callableStatement.getString(i));
}
}
注意:mybatis-config.xml中不需要配置,否则全局生效。
只需要在对应的Mapper.xml中做对应修改:
插入sql增加typeHandler
INSERT INTO table_name (id,name,idCardNo) VALUES (#{id},#{name},#{idCardNo,jdbcType=VARCHAR,typeHandler=com.bing.core.persistence.SimpleTypeHandler})
查询结果映射增加typeHandler
到此所有工作完成。mybatis不但内置了大量的typeHandler,而且还为我们提供了一个常用的枚举类typeHandler: EnumTypeHandler 和 EnumOrdinalTypeHandler,可以直接使用。
-
官方文档:http://www.mybatis.org/mybatis-3/zh/configuration.html#typeHandlers