mybatis进阶之typeHandler

前言: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<String> {
    @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使其生效:

<typeHandlers>
        <typeHandler handler="com.bing.core.persistence.SimpleTypeHandler" jdbcType="VARCHAR" javaType="java.lang.String"/>
</typeHandlers>

在配置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<String> {
    @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 id="addActivity">
        INSERT INTO table_name (id,name,idCardNo) VALUES (#{id},#{name},#{idCardNo,jdbcType=VARCHAR,typeHandler=com.bing.core.persistence.SimpleTypeHandler})
 </insert>

查询结果映射增加typeHandler

<resultMap id="Base_ResultMap" type="Activity">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="idCardNo" property="idCardNo" typeHandler="com.bing.core.persistence.SimpleTypeHandler" jdbcType="VARCHAR"/>
</resultMap>

到此所有工作完成。mybatis不但内置了大量的typeHandler,而且还为我们提供了一个常用的枚举类typeHandler: EnumTypeHandler EnumOrdinalTypeHandler,可以直接使用。

转载于:https://my.oschina.net/firstbing/blog/1593353

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值