在JDBC中,需要在PreparedStatement对象中设置那些已经预编译过的SQL语句的参数。执行SQL后,会通过ResultSet对象获取得到数据库的数据,而这些MyBatis是根据数据的类型typeHandler来实现的。在typeHandler中,分为jdbcType和javaType,其中jdbcType用于定义数据库类型,而javaType用于定义java类型,那么typeHandler的作用就是承担jdbcType和javaType之间的相互转化。
typeHandler分为3类:
系统定义的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;
}
这里我们稍微说一下它的定义:
在编写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的源码:
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个抽象方法。