什么是TypeHandler?
在mapper,xml中,我们可能见过这种写法:
is_completed = #{isCompleted,typeHandler=cn.web.common.typehandler.String2IntTypeHandler}
我们知道正常的写法后面跟的是jdbctype 例如:
<update id="deleteClass" parameterType="java.lang.String">
DELETE FROM aim_class_t WHERE class_code = #{value,jdbcType=VARCHAR}
</update>
TypeHandler的作用
1.例如当你存入List类型数据导数据库,自动转换为varchar类型,并且List中的每个元素间用“,”分割开
2.又例如当你读取varchar类型的数据,将读取结果自动转换为List,以每个“,”分割
3.它的作用不仅仅是这些,他主要的作用是在数据库和java中间操作数据格式
TypeHandler的配制与使用
使用TypeHandler的两种方式
- 实现TypeHandler接口
- 继承BaseTypeHandler类
举一个工作中遇到的例子,采用了继承BaseTypeHandler类的方法:
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
@MappedTypes(String.class) //定义了被拦截的Java类型
@MappedJdbcTypes(JdbcType.INTEGER) //必须要是枚举类org.apache.ibatis.type.JdbcType所枚举的数据类型
public class String2IntTypeHandler extends BaseTypeHandler<String> {
@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);
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType) throws SQLException {
if (parameter!=null&¶meter.length()>0)
ps.setInt(i, Integer.parseInt(parameter));
else
ps.setNull(i, Types.INTEGER);
}
}
当我们调用这个TypeHandler之后,对数据库的操作都会经过此方法,类似于过滤器一样,在setNonNullParameter方法中重写需要写入数据库的数据,其他的为读取转换。
上面完成了读取写入的转换重写,下面就是在xml中具体的配置了
<insert id="addCourse" parameterType="AmcCourse">
INSERT INTO amc_course_base_t (
course_code,
course_title,
course_logo,
course_score,
content_type_id,
course_kind_id,
course_keywords,
course_desc,
std_fee
)
VALUES
(
#{courseCode,jdbcType=VARCHAR},
#{courseTitle,jdbcType=VARCHAR},
#{courseLogo,jdbcType=VARCHAR},
#{courseScore,typeHandler=cn.aim.web.typehandler.String2FloatTypeHandler},
#{contentTypeId,typeHandler=cn.aim.web.typehandler.String2IntTypeHandler},
#{courseKindId,typeHandler=cn.aim.web.typehandler.String2IntTypeHandler},
#{courseKeywords,jdbcType=VARCHAR},
#{courseDesc,jdbcType=VARCHAR},
#{stdFee,typeHandler=cn.aim.web.typehandler.String2IntTypeHandler},
)
</insert>
在上面的代码中我们可以看出,其中几个字段将原本的jdbcType替换成了typeHandler,值也由JdbcType所枚举的数据类型,改为了刚刚我们配置的TypeHandler类,说明一点 每个表达式中都可以同时写javaType,jdbcType和TypeHandler,也可以只写一个
读取数据也可以在resultMap中配置,举个例子:
<resultMap id="String2IntTypeHandler" type="cn.aim.web.entity.CourseEntity">
<result typeHandler="cn.aim.web.typehandler.String2IntTypeHandler" column="content_type_id" javaType="java.lang.String"
jdbcType="Int"
property="contentTypeId"/>
</resultMap>
这样写的弊端在于只对返回此resultMap的查询语句有效。
最后在Mybatis的config文件中配置
<!--启动时会扫描包下的所有文件-->
<typeHandlers>
<package name="cn.aim.web.typehandler"/>
</typeHandlers>
<!--或单个写入要注册的TypeHandler-->
<typeHandlers>
<typeHandler handler="cn.aim.web.typehandler.String2IntTypeHandler"/>
</typeHandlers>
总结
总的来说TypeHandler可以理解为java于Mybatis中间的过滤器,不论是写入也好,读取也罢,数据经过注册、配置后的TypeHandler,转换为相应的数据格式。