mybatis从使用到了解(五)_mybatis类型映射(TypeHandler)

mybatis的TypeHandler类型转换

java有java的数据类型,数据哭有数据库的类型,当我们把java数据插入数据库的时候,需要讲java数据类型转化为数据库数据类型;当我们从数据库读取数据的时候,需要把数据库类型转化为java类型来处理。这中间的转化,mybatis中是通过TypeHandler类型处理器来处理的。

我们先通过一个例子来了解TypeHandler的实现机制

在这个例子中讲java字符数组String[]转化成数据库varchar类型。如:String[] interests = {"movie", "music"}转为”movie,music",同时也能实现从varchar转化为String[] 数组。

  • 自定义类型转化器
@MappedTypes({String[].class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class StringArrayTypeHandler extends BaseTypeHandler{
    /**
     * 把Java类型参数转换为对应的数据库类型
     * @param ps 当前的PreparedStatement对象
     * @param i 当前参数位置
     * @param parameter 当前参数的Java对象
     * @param jdbcType 当前参数的数据库类型
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException {
        // 由于BaseTypeHandler中已经把parameter为null的情况做了处理,所以这里我们就不用在判断parameter是否为空,直接用就可以了
        StringBuffer result = new StringBuffer();
        for (String value : parameter) {
            result.append(value).append(",");
        }
        result.deleteCharAt(result.length() - 1);
        ps.setString(i, result.toString());
    }

    /**
     * 获取数据结果集时把数据库类型转换为对应的Java类型
     * @param rs 当前的结果集
     * @param columnName 当前的字段名称
     * @return  转换后的Java对象
     * @throws SQLException
     */
    @Override
    public String[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return this.getStringArray(rs.getString(columnName));
    }

    /**
     * 通过字段位置获取字段数据时把数据库类型转换为对应的Java类型
     * @param rs 当前的结果集
     * @param columnIndex 当前字段的位置
     * @return 转换后的Java对象
     * @throws SQLException
     */
    @Override
    public String[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return this.getStringArray(rs.getString(columnIndex));
    }

    /**
     * 调用存储过程后把数据库类型的数据转换为对应的Java类型
     * @param cs  当前的CallableStatement执行后的CallableStatement
     * @param columnIndex  当前输出参数的位置
     * @return
     * @throws SQLException
     */
    @Override
    public String[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return this.getStringArray(cs.getString(columnIndex));
    }

    /**
     * 讲”movie,music"转化为数组对象
     * @param columnValue
     * @return
     */
    private String[] getStringArray(String columnValue) {
        if (columnValue == null)
            return null;
        return columnValue.split(",");
    }
}
  • 配置文件里配置自定义的TypeHandler

    
    

如果在自定义类型转化器时通过注解标注了对应的javaType以及jdbcType,则在配置文件中不需要再次声明;如果没有,则需要在配置文件中说明avaType和jdbcType。

  • 声明包含String[]数组的学生类
public class Student {
    private int student_id;
    private String student_name;
    private int student_age;
    private String student_phone;
    private String[] interests;
    public Student() {
        super();
    }
    public int getStudent_id() {
        return student_id;
    }
    public void setStudent_id(int student_id) {
        this.student_id = student_id;
    }
    public String getStudent_name() {
        return student_name;
    }
    public void setStudent_name(String student_name) {
        this.student_name = student_name;
    }
    public int getStudent_age() {
        return student_age;
    }
    public void setStudent_age(int student_age) {
        this.student_age = student_age;
    }
    public String getStudent_phone() {
        return student_phone;
    }
    public void setStudent_phone(String student_phone) {
        this.student_phone = student_phone;
    }
    public String[] getInterests() {
        return interests;
    }
    public void setInterests(String[] interests) {
        this.interests = interests;
    }
    @Override
    public String toString() {
        return "Student{" +
                "student_id=" + student_id +
                ", student_name='" + student_name + '\'' +
                ", student_age=" + student_age +
                ", student_phone='" + student_phone + '\'' +
                ", interests=" + Arrays.toString(interests) +
                '}';
    }
}
  • 在stutent.xml中增加sql语句

    
    
    
    
    



    insert into student (student_name,student_age,student_phone,interests) values
    (#{student_name},#{student_age},#{student_phone},#{interests,javaType=[Ljava.lang.String;,jdbcType=VARCHAR})



  • 测试类
/**
 * 方式4
 * @throws IOException
 */
public static void test04() throws IOException {
    // 读取配置文件
    Reader reader = Resources.getResourceAsReader("config.xml");
    // 创建SqlSeessionFactory工厂
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    Student student = new Student();
    String[] interests = {"movie", "music"};
    student.setInterests(interests);
    student.setStudent_age(12);
    student.setStudent_name("yongsheng.su");
    student.setStudent_phone("123456");
    // 执行sql
    SqlSession session = sqlSessionFactory.openSession();
    try {
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        int result = mapper.insertStudent(student);
        System.out.println(result);
        session.commit();
    } finally {
        session.close();
    }
}

public static void test05() throws IOException {
    // 读取配置文件
    Reader reader = Resources.getResourceAsReader("config.xml");
    // 创建SqlSeessionFactory工厂
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

    Student student = null;
    // 执行sql
    SqlSession session = sqlSessionFactory.openSession();
    try {
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        student = mapper.selectStudent(7);
        System.out.println(student);
        session.commit();
    } finally {
        session.close();
    }
    System.out.println(student);
}

mybatis类型映射实现说明

通过上面的例子,可以发现要实现自定义TypeHandler,只需要继承BaseTypeHandler,然后实现相应的转换规则就可以。其实除了继承BaseTypeHadler以外,还可以自己实现TypeHandler。通过下面代码,可以发现,BaseHandler也是继承自TypeHandler,并提供了一些默认的实现,对null值做了一些处理,这样我们继承BaseTypeHandler时就不需要对null值做处理了。

  • TypeHandler接口
public interface TypeHandler {
  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;
}
  • BaseTypeHandler类实现
public abstract class BaseTypeHandler extends TypeReference implements TypeHandler {
  protected Configuration configuration;
  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 {
    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 {
    T result;
    try {
      result = getNullableResult(rs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from result set.  Cause: " + e, e);
    }
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }
  @Override
  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
    T result;
    try {
      result = getNullableResult(cs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from callable statement.  Cause: " + e, e);
    }
    if (cs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }

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

mybatis提供的默认类型

对于一些常用的java类型,mybatis已经提供了相应的TypeHandler,并且会自动注册他们。mybatis提供了以下集中类型转换器。

register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

参考文章:http://4443915.blog.51cto.com/4433915/1828533

你可能感兴趣的:(mybatis从使用到了解(五)_mybatis类型映射(TypeHandler))