Mybatis TypeHandler类型转换器


TypeHandler类型转换器


1,概述:

我们思考一个问题,我们之前在是使用JDBC的时候,我们从ResultSet获取对应的数据,用到了对应getXXX方法。比如获取一个数据库为int的数据,我们可以使用rs.getInt(),如果我们获取数据库类型为varchar的数据,我们可以使用rs.getString()。

而我们现在使用了Mybatis之后,从数据库里面查询出来了之后,他是如何把数据库的类型和Java类型对应起来的呢?这个地方Mybatis就用到了typeHandler来实现。


2,设计思路:

在typeHander里面提出了两个类型。一个叫做jdbcType,一个叫做javaType。jdbcType表示数据库中的字段类型,另外一个javaType表示对应的PO中的java的类型。而我们的typeHander承担的就是把jdbcType和JavaType相互转换的作用。

image


3,系统自定义typeHandler:

Mybatis自己已经给我们定义好了很多typeHandler了,这里我们截图说明一下:

类型处理器Java类型JDBC类型
BooleanTypeHandlerjava.lang.Boolean,boolean数据库兼容的 BOOLEAN
ByteTypeHandlerjava.lang.Byte,byte数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandlerjava.lang.Short,short数据库兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandlerjava.lang.Integer,int数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandlerjava.lang.Long,long数据库兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandlerjava.lang.Float,float数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandlerjava.lang.Double,double数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandlerjava.lang.StringCHAR、VARCHAR
ClobReaderTypeHandlerjava.io.Reader——
ClobTypeHandlerjava.lang.StringCLOB、LONGVARCHAR
NStringTypeHandlerjava.lang.StringNVARCHAR、NCHAR
NClobTypcHandlerjava.lang.StringNCLOB
BlobInputStreamTypeHandlerjava.io.InputStream——
ByteArrayTypeHandlerbyte[]数据库兼容的字节流类型
BlobTypeHandlerbyte[]BLOB、LONGVARBINARY
DateTypeHandlerjava.util.DateTIMESTAMP
DateOnlyTypeHandlerjava.util.DateDATE
TimeOnlyTypeHandlerjava.util.DateTIME
SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP
SqlDateTypeHandlerjava.sql.DateDATE
SqlTimeTypeHandlerjava.sql.TimeTIME
ObjectTypeHandlerAnyOTHER或未指定类型
EnumTypeHandlerEnumeration TypeVARCHAR 任何兼容的字符串类型,存储枚举的名称(而不是索引)
EnumOrdinalTypeHandlerEnumeration Type任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)

上面就是Mybatis自带的typeHandler。在大部分的情况下无须显式地声明jdbcType javaType,因为MyBatis系统会自己检测。


4,分析typeHandler实现思路

我们这里要自定义类型转换器,我们先参考一下Mybatis自己定义的类型转换器。

这里我们就用最常用StringTypeHandler来举例。我们跟踪了一下代码,我们发现StringTypeHandler继承了BaseTypeHandler,BaseTypeHandler实现了TypeHandler接口。

1,分析TypeHandler接口:

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public interface TypeHandler<T> {

  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; 
  T getResult(ResultSet rs, String columnName) throws SQLException;

  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}


1,这里有个泛型T,这个泛型就是表示我们的JavaType。比如我们的PO中的某个属性的是String类型,我们就可以把这个T写成String。这里,我们在ResultMap中某个属性上面配置,Mybatis就会自动检查我们对应属性的Java类型,然后设置过来。

2,setParameter方法,使用typeHandler通过PreparedStatement对象进行设置sql参数的时候调用的具体方法。其中i表示Sql参数的下表,parameter是参数,jdbcType表示数据库类型。

3,getResult方法:它的作用就是从jdbc结果集中获取数据进行转换。要么使用列表,要么使用下标。其中最后一个getResult是存储过程用的,我们不说。

2,分析BaseTypeHandler抽象类:

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
  @Deprecated
  protected Configuration configuration;
  @Deprecated
  public void setConfiguration(Configuration c) {
    this.configuration = c;
  }

  @Override
  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
              + "Cause: " + e, e);
      }
    } else {
      try {
        setNonNullParameter(ps, i, parameter, jdbcType);
      } catch (Exception e) {
        throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different configuration property. "
              + "Cause: " + e, e);
      }
    }
  }

  @Override
  public T getResult(ResultSet rs, String columnName) throws SQLException {
    try {
      return getNullableResult(rs, columnName);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);
    }
  }

  @Override
  public T getResult(ResultSet rs, int columnIndex) throws SQLException {
    try {
      return getNullableResult(rs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set.  Cause: " + e, e);
    }
  }

  @Override
  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
    try {
      return getNullableResult(cs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement.  Cause: " + e, e);
    }
  }

  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
}


1,我们在TypeHandler接口里面定义的方法,在本类当中都被实现了,但是,它是通过直接调用对应的抽象方法来实现的。

2,setParameter方法:当parameter和jdbcType同时为空的时候,Mybatis将抛出异常,如果能明确jdbcType,则会进行空设置。如果parameter不为空那么它讲采用setNotNullParameter方法来设置。而setNotNullParameter也是一个抽象方法,我们在自定义的TypeHandler中进行实现。

3,getResult方法:通过调用getNullableResult方法来获取,如果判断为空返回null。getNullableResult也是一个抽象方法,我们也需要在子类中实现。

最后

从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。

因为入门学习阶段知识点比较杂,所以我讲得比较笼统,大家如果有不懂的地方可以找我咨询,我保证知无不言言无不尽,需要相关资料也可以找我要,我的网盘里一大堆资料都在吃灰呢。

干货主要有:

①1000+CTF历届题库(主流和经典的应该都有了)

②CTF技术文档(最全中文版)

③项目源码(四五十个有趣且经典的练手项目及源码)

④ CTF大赛、web安全、渗透测试方面的视频(适合小白学习)

⑤ 网络安全学习路线图(告别不入流的学习)

⑥ CTF/渗透测试工具镜像文件大全

⑦ 2023密码学/隐身术/PWN技术手册大全

扫码领取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值