MyBatis配置文件详谈——typeHandler类型转换器

在JDBC中,需要在PreparedStatement对象中设置那些已经预编译过的SQL语句的参数。执行SQL后,会通过ResultSet对象获取得到数据库的数据,而这些MyBatis是根据数据的类型typeHandler来实现的。在typeHandler中,分为jdbcType和javaType,其中jdbcType用于定义数据库类型,而javaType用于定义java类型,那么typeHandler的作用就是承担jdbcType和javaType之间的相互转化。
typeHandler分为3类:

  • 系统定义的typeHandler
  • 自定义typeHandler
  • 枚举typeHandler

系统定义的typeHandler
在MyBatis中typeHandler都要实现接口org.apache.ibatis.TypeHandler,首先让我们先看看这个接口的定义,代码如下:

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;
}

这里我们稍微说一下它的定义:

  • 其中T是泛型,专指javaType,比如我们需要String的时候,那么实现类可以写为implements TypeHandler String。
  • setParameter方法:是使用typeHandler通过PreparedStatement对象进行设置SQL参数的时候使用的具体方法,其中i是参数在SQL的下标,parameter是参数,jdbcType是数据库类型
  • 其中有3个getResult的方法,它的作用是从JDBC结果集中获取数据进行转换,要么使用列名(columnName)要么使用下标(columnIndex)获取数据库的数据,其中最后一个getResult方法是存储过程专用的。

在编写typeHandler前,先来研究一下MyBatis系统的typeHandler是如何实现的,所以有必要先研究一下MyBatis系统的typeHandler。首先它是继承了org.apache.ibatis.type.BaseTypeHandler,而BaseTypeHandler的代码如下:

public abstract class BaseTypeHandler<T> extends TypeReference implements TypeHandler<T> {

    @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 thid parameter or a different jdvcTtpeForNull configuration property."
                        +"Cause:"+e,e);
            }
        }
        else {
            try {
                setNonNullParameter(ps,i,parameter,jdbcType);
            }catch (Exception e){
                throw new TypeException("Error setting null for parameter #"+i+"with jdbcType"+jdbcType+"."+
                        "Try setting a different jdbcType for thid parameter or a different jdvcTtpeForNull configuration property."
                        +"Cause:"+e,e);
            }
        }
    }

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

    @Override
    public T getResult(ResultSet rs,int columnIndex) throws SQLException{
       // ......
    }

    @Override
    public T getResult(CallableStatement cs, int columnIndex) throws SQLException{
       // ......
    }

    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;
}

简单分析一下BaseTypeHandler的源码:

  • BaseTypeHandler是一个抽象类,需要子类去实现其定义的4个抽象方法,而它本身实现了typeHandler接口的4个方法。
  • getResult方法,非空结果集是通过getNullableResult方法获取。如果判断为空,则返回null。
  • setParameter方法,当参数parameter和jdbcType同时为空时,MyBatis将抛出异常,如果能明确jdbcType,则会进行空设置;如果参数不为空,那么它将采用setNonNullParameter方法进行设置参数。
  • getNullableParameter方法用于存储过程。

MyBatis使用最多的typeHandler之一——StringHandler,它用于字符串转换,其源码如下:

public class StringTypeHandler 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);
    }

显然代码也很简单,实现了BaseTypeHandler的4个抽象方法。

你可能感兴趣的:(MyBatis配置文件详谈——typeHandler类型转换器)