本篇文章用来记录作者自己的学习过程 ,在这个过程中参考了以下作者的文章:
http://elim.iteye.com/blog/1847854#_Toc353481987

TypeHandler的由来
java有java的数据类型,数据库有数据库的类型,大家都知道在jdbc中我们两者之间的转换都需要自己写代码实现,typeHandler就是为了解决两者之间的自动的转换

TypeHandler接口介绍
typeHandler就是为了解决两者之间的自动的转换,那么它需要做一下几件事情
参数设置的转换(jdbc中的形式 stmt.setInt(1, 1) 不熟悉的话建议去回忆一下jdbc)
获取到结果集的转换: 数据库表字段的名称 表字段的位置 除了简单sql还有存储过程
以上需要做几件事 ,就定义了几种方法

TypeHandler接口代码如下:

public interface TypeHandler<T> {
  /**
   * 类型转换接口       这个能体现怎么设计一个接口  是自己比较欠缺的   
   * java 与数据库 之间的转换 (抽象一下  需要做哪几件事情)  
   * 参数设置的转换
   * 获取到结果集的转换: 数据库表字段的名称 表字段的位置  除了简单sql还有存储过程  
   * @param ps
   * @param i
   * @param parameter
   * @param jdbcType
   * @throws SQLException
   */
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
    /**
     * 
     * @param rs
     * @param columnName
     * @return
     * @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;

}

我们有一个类JiKeUser,里边有个属性interests,是个String[],存入数据库是它拼接,我们怎么来实现这个转换过程呢
JikeUser源码:

public class JiKeUser {
    private int id;
    private String userName;
    private String password;
    //需要把它以拼接字符串的形式存到数据库中,然后在取出来的时候又把它还原为一String 数组
    private String[] interests;  
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String[] getInterests() {
        return interests;
    }
    public void setInterests(String[] interests) {
        this.interests = interests;
    }

    @Override  
    public String toString() {  
       return "User [ id=" + id + ", interests="  
              + Arrays.toString(interests) + ", userName=" + userName + "]";  
    }

创建StringArrayTypeHandler继承TypeHandler,用来实现java到数据库的互相转换

/**
 * 自己实现的一个TypeHandler 类  用于java 数据库类型的转换
 * @author hc
 *
 */
public class StringArrayTypeHandler implements TypeHandler<String[]>{

    @Override
    public void setParameter(PreparedStatement ps, int i, String[] parameter,
            JdbcType jdbcType) throws SQLException {
        if(parameter==null){
            ps.setNull(i, Types.VARCHAR);
        }else{
            //在这里边具体实现 java对象到数据库的转换
            StringBuffer sb=new StringBuffer();
            for(int j=0;i<parameter.length;j++)
                sb.append(parameter[j]).append(",");
            ps.setString(i,sb.toString());
        }

    }

    @Override
    public String[] getResult(ResultSet rs, String columnName) throws SQLException {
        String columnValue=rs.getString(columnName);
        return getStringArray(columnValue);
    }

    @Override
    public String[] getResult(ResultSet rs, int columnIndex) throws SQLException {
        String columnValue=rs.getString(columnIndex);
        return getStringArray(columnValue);
    }

    @Override
    public String[] getResult(CallableStatement cs, int columnIndex)
            throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 字符串转换为数组
     * @param columnValue
     * @return
     */
     private String[] getStringArray(String columnValue) {  
         if (columnValue == null)  
                return null;  
         return columnValue.split(",");  
  }

接下来我们就需要注册我们实现的Typehandler,注册分为两种方式
a.在配置文件中定义typehandlers的子元素typehanlder来注册,该方式一次只能注册一个,另外还有两个属性需要指定,javatype java的类型 jdbctype数据库中的类型,除了在xml 文件直接配置上边的两个属性以外,还可以用注解的形式在StringArrayTypeHandler 类开头指定类型(@MappedJdbcTypes({JdbcType.VARCHAR}) )
b.在在配置文件中定义typehandlers的子元素package来注册,该种方式可以注册包下边的所有typehandler,jdbctype和javatype只能通过注解的形式指定

下边以XML 举例 完成java数组 和数据库Varchar的注册

<typeHandlers>  
      <typeHandler handler="my.book.business.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  
    </typeHandlers>

则Mybatis在实际注册的时候是以javaType为String数组,jdbcType为VARCHAR来注册StringArrayTypeHandler的。

mybatis自动获取我们刚刚注册的typehandler
jikeUser.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="/">

  <resultMap type="my.book.pojo.JiKeUser" id="jikeUser"> 
    <result property="id" column="id"/>
    <result property="userName" column="use_name"/>
    <result property="password" column="password"/>
    <result column="interests" property="interests" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  
  </resultMap>

  <select id="findById"  parameterType="int"  resultMap="jikeUser">
        select * from jikeUser where id=#{id}
  </select>


</mapper>

这个时候Mybatis就会到已经注册了的TypeHandler中寻找到能处理javaType和jdbcType对应的类型转换的TypeHandler来进行处理。在这里就会找到我们注册的StringArrayTypeHandler.

文章写道这里,上边只是一种最基本的注册获取方式,除了可以用注解代替外一下罗列的情况也是可以的
A. 不动StringArrayTypeHandler的注册信息,jikeUser.xml修改如下

<result column="interests" property="interests" jdbcType="VARCHAR"/>

过程分析:首先它发现我们的interests没有指定javaType,这个时候它就会通过我们指定的类型User和属性interests获取User类的interests属性对应的java类型,即String数组,再拿着获取到的javaType和我们指定的jdbcType即VARCHAR去寻找对应的TypeHandler,这个时候就找到了我们之前以String数组和VARCHAR注册好的StringArrayTypeHandler来处理interests的类型转换
B 注册和查找的jdbctype 不设置 这时候按照 javatype jdbctype=null typeHandler注册和查找
C。结合AB完成最简单,在A的基础上 注册和查找的jdbctype 不设置