在最近的学习中遇到TypeHandler这个接口,它是在org.apache.ibatis.type这个包下,实现这个接口的类,配置好之后可以默认的将数据库中对应的格式转化成Java中相应的格式,简单的来说就是一个格式转换器。正如百度百科中介绍的,MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。关于mybatis的更多的信息,请查看此博客的另一篇文章。
每当MyBatis 设置参数到PreparedStatement 或者从ResultSet 结果集中取得值时,就会使用TypeHandler 来处理数据库类型与java 类型之间转换。在MyBatis中默认设置了很多TypeHandlers,比如BooleanTypeHandler转换jdbc任何兼容的BOOLEAN成java类型Boolean, boolean ,常用的还有DateTypeHandler,转换jdbc的TIMESTAMP到Java的java.sql.Date。
在MyBatis的用户指南中,有这么一段:
您能够重写类型处理器(type handlers),或者创建您自己的类型处理器去处理没有被支持的或非标准的类型。要做到这一点,只要实现TypeHandler 接口(org.mybatis.type),并且将您的TypeHandler 类映射到java 类型和可选的
JDBC 类型即可。例如:
// ExampleTypeHandler.java
public class ExampleTypeHandler implements TypeHandler {
public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, (String) parameter);
}
public Object getResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getString(columnName);
}
public Object getResult(CallableStatement cs, int columnIndex)
throws SQLException {
return cs.getString(columnIndex);
}
}
<pre name="code" class="html">// MapperConfig.xml
<typeHandlers>
<typeHandler javaType="String" jdbcType="VARCHAR"
handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
使用上面的TypeHandler 将会重写已经存在的用来处理java 的String 属性、VARCHAR 参数和结果集的类型处理器。注意,MyBatis 并不会通过数据库的元数据来确认类型,所以您必须指定它的一个类型处理器,用于将VARCHAR 字段的参数和结果映射到正确的类型上。这是因为
MyBatis 在语句的执行之前都不知道它要处理的数据类型是什么。
但是在实际的操作中有些不一样,在实现接口的时候是4个方法,上述的代码中还少了一个方法,方法如下。个人理解,这里面的getResult方法是从数据库中拿值的时候进行的转化,而setParameter函数则是存值的时候需要用到的。下面的方法与上面的那个getResult方法很像,只是一个columnName参数不一样,只是简单的重载。
public Object getResult(ResultSet rs, int columnName)
throws SQLException {
return rs.getString(columnName);
}
还有关于配置的时候经常出现找不到类的情况,所以建议在配置路径之后按住Ctrl键鼠标放在路径上面看看路径是否能找到,这也是一个常用的实用小技巧。
之后自己自定义了一个HotelTypeHandler。
在代码中涉及到一个枚举类,即HotelTypeEnum,其代码如下
package hotel.Enum;
public enum HotelTypeEnum {
CHAIN("CHAIN","连锁酒店"),
SUPERHOTEL("SUPERHOTEL","高级酒店");
private String title;
private String value;
private HotelTypeEnum(String title,String value){//枚举的构造就只能是私有的防止外部修改
this.title = title;
this.value = value;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
实现了了TypeHandler接口的类,代码如下
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import com.hotel.enmu.HotelTypeEnum;
public class HotelTypeHander implements TypeHandler<HotelTypeEnum>{
@Override
public HotelTypeEnum getResult(ResultSet arg0, String arg1)
throws SQLException {
return HotelTypeEnum.valueOf(arg0.getString(arg1));
}
@Override
public HotelTypeEnum getResult(ResultSet arg0, int arg1) throws SQLException {
return HotelTypeEnum.valueOf(arg0.getString(arg1));
}
@Override
public HotelTypeEnum getResult(CallableStatement arg0, int arg1)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setParameter(PreparedStatement arg0, int arg1,
HotelTypeEnum arg2, JdbcType arg3) throws SQLException {
// TODO Auto-generated method stub
}
}
然后在MyBatis配置文件中加上
<pre name="code" class="html"><typeHandlers>
<typeHandler handler="hotel.tools.HotelTypeHandler"
javaType="hotel.Enum.HotelTypeEnum" jdbcType="VARCHAR" />
</typeHandlers>
测试了一下,可以正确的转化,还有一种配置的方法就是在SqlMapper.xml文件中ResultMap标签下的result标签可以添加TypeHandler属性,只转化这一个查询ResultMap里的值。上一种方式则是全局的转化。
代码举例:
<resultMap type="hotelVO" id="hotelVOResult">
<result column="id" property="h_id"/>
<result column="h_name" property="hname"/>
<result column="h_type" property="htype" typeHandler="hotel.tools.HotelTypeHandler"/>
<!-- 其他的很多名字都是和数据库中的名字是一致的,可以直接映射,不需要配 -->
</resultMap>
测试这两种方式都是可行的。
有什么不足的地方请多指教。