一、引言
最近在做一個客戶端日誌統計分析的模塊,被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;