一、引言
最近在做一个客户端日志统计分析的模块,被Java实体类中属性类型与数据库字段属性匹配问题搞的头大。抽个时间,对Mybatis中自定义TypeHandler做一个总结吧。
简单描述一下需求:客户端上报日志接口中,有一个异常内容字段,对应Java实体类excepContent属性,类型为String(此处应该定义为byte[]类型),对应的数据库中的字段为excp_content,类型为blob。
当我们拿到这样一个实体类往数据库中插入数据时,毫无疑问,会报类型不匹配异常,读取时也会报异常。
二、自定义TypeHandler
上面的问题怎么解决呢?这就需要自定义一个TypeHandler类型处理器。实现TypeHandler接口或继承BaseTypeHander都可以。
@MappedJdbcTypes(JdbcType.BLOB) // 声明数据库中对应数据类型
@MappedTypes(value = String.class) // 转化后的数据类型
public class CustomBlobTypeHandler extends BaseTypeHandler<String> {
// 数据插入数据库时调用此方法
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType)
throws SQLException {
// 声明一个输入流对象
ByteArrayInputStream bis = null;
try {
// 把字符串转为字节流
bis = new ByteArrayInputStream(parameter.getBytes("gbk"));
} catch (Exception e) {
throw new RuntimeException("Blob Encoding Error!");
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
throw new RuntimeException("Blob Encoding Error!");
}
}
}
ps.setBinaryStream(i, bis, parameter.length());
}
// 从数据库中读取数据时调用此方法
@Override
public String getNullableResult(ResultSet rs, String columnName)
throws SQLException {
Blob blob = (Blob) rs.getBlob(columnName);
byte[] returnValue = null;
if (null != blob) {
returnValue = blob.getBytes(1, (int) blob.length());
}
try {
//将取出的流对象转为utf-8的字符串对象
return new String(returnValue, "gbk");
} catch (Exception e) {
throw new RuntimeException("Blob Encoding Error!");
}
}
// 读取方法同上,方法重载
@Override
public String getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
Blob blob = (Blob) rs.getBlob(columnIndex);
byte[] returnValue = null;
if (null != blob) {
returnValue = blob.getBytes(1, (int) blob.length());
}
try {
// 将取出的流对象转为utf-8的字符串对象
return new String(returnValue, "gbk");
} catch (Exception e) {
throw new RuntimeException("Blob Encoding Error!");
}
}
// 读取方法同上,方法重载
@Override
public String getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
Blob blob = (Blob) cs.getBlob(columnIndex);
byte[] returnValue = null;
if (null != blob) {
returnValue = blob.getBytes(1, (int) blob.length());
}
try {
//将取出的流对象转为utf-8的字符串对象
return new String(returnValue, "gbk");
} catch (Exception e) {
throw new RuntimeException("Blob Encoding Error!");
}
}
}
自定义的TypeHandler类型处理器写好了,很简单。但怎么让这个自定义处理器起作用呢?这就需要在配置文件中配置。
三、如何配置
关于如何让自定义TypeHandler生效,分两种情况。一种是Mybatis配置,另一种是tk.mybatis配置。
1、Mybatis配置
此情况下,又分为两种情况。
(1)、全局配置
mybatis:
config-location: classpath:mybatis-config.xml # mybatis配置文件位置
mapperLocations: classpath:mapper/*.xml # mybatis mapper文件位置
typeAliasesPackage: com.example.domain # java实体类所在包
type-handlers-package: com.scorpios.analyse.typehandler # 自定义TypeHandler所在包
此种配置方式,全局有效,不用其他任何配置。
(2)、局部配置:在处理某个字段时,设置typeHandler。比较繁琐。
在数据插入时,我们可以做如下指定:
#{excpContent,typeHandler="com.scorpios.analyse.typehandler.CustomBlobTypeHandler"}
数据读取时,我们可以用<resultMap>
来封装,在属性后面指定typeHandler属性即可。
<result column="excp_content" property="excpContent" typeHandler="com.scorpios.analyse.typehandler.CustomBlobTypeHandler" />
注意:如果在参数位置修改TypeHandler,应该保证保存数据和查询数据用的TypeHandler是一样的。
2、tk.mybatis配置
(1)、全局级别:在 MyBatis 配置文件中配置 typeHandlers。和上述全局配置一样。
(2)、字段级别:@ColumnType 注解
@ColumnType(typeHandler=CustomBlobTypeHandler .class)
private String excpContent;