1. 程式人生 > 實用技巧 >Mybatis中的TypeHandler-測試

Mybatis中的TypeHandler-測試

1.TypeHandler概念
TypeHandler,型別轉換器,在mybatis中用於實現java型別和JDBC型別的相互轉換.mybatis使用prepareStatement來進行引數設定的時候,需要通過typeHandler將傳入的java引數設定成合適的jdbc型別引數,這個過程實際上是通過呼叫PrepareStatement不同的set方法實現的;在獲取結果返回之後,也需要將返回的結果轉換成我們需要的java型別,這時候是通過呼叫ResultSet物件不同型別的get方法時間的;所以不同型別的typeHandler其實就是呼叫PrepareStatement和ResultSet的不同方法來進行型別的轉換,有些時候會在呼叫PrepareStatement和ResultSet的相關方法之前,可以對傳入的引數進行一定的處理.
當我們沒有指定typeHandler的時候mybatis會根據傳入引數的型別和返回值的型別呼叫預設的typeHandler進行處理.對於一個typeHandler需要配置java型別(javaType)和JDBC型別(jdbcType),typeHandler的作用就是實現這兩種型別的轉換,在傳入的引數為指定的Java型別時,將其轉換為指定的JDBC型別,當返回值為指定JDBC型別時將其轉換為配置的Java型別.

2.mybatis預設定義的TypeHandler
mybatis預設定義了一批TypeHandler,正常情況下這些TypeHandler就可以滿足我們的使用了.mybatis通過TypeHandlerRegister來管理TypeHandler

3.使用自定義TypeHandler

示例程式碼:

import lombok.extern.slf4j.Slf4j;
import oracle.sql.DATE;
import oracle.sql.TIMESTAMP;
import oracle.sql.TIMESTAMPLTZ;
import oracle.sql.TIMESTAMPTZ;
import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; import java.sql.*; @MappedTypes({Object.class}) @MappedJdbcTypes({JdbcType.TIMESTAMP}) @Slf4j @Component public class MyObjectTypeHandle extends
BaseTypeHandler<Object> { public MyObjectTypeHandle(){ } @Override public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { ps.setObject(i,parameter); } @Override public Object getNullableResult(ResultSet rs, String columnName) throws SQLException { try { Object result = rs.getObject(columnName); return result==null?null:dealResult(result); } catch (SQLException e) { e.printStackTrace(); log.error(e.getMessage()); return null; } } @Override public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException { try { Object result = rs.getObject(columnIndex); return result==null?null:dealResult(result); } catch (SQLException e) { e.printStackTrace(); log.error(e.getMessage()); return null; } } @Override public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { try { Object result = cs.getObject(columnIndex); return result==null?null:dealResult(result); } catch (SQLException e) { e.printStackTrace(); log.error(e.getMessage()); return null; } } private Object dealResult(Object result) throws SQLException{ if (result instanceof TIMESTAMP) { return ((TIMESTAMP) result).timestampValue().getTime(); }else if(result instanceof DATE){ return new Date(((DATE)result).dateValue().getTime()); }else if(result instanceof TIMESTAMPLTZ){ return new Date(((TIMESTAMPLTZ)result).dateValue().getTime()); }else if(result instanceof TIMESTAMPTZ){ return new Date(((TIMESTAMPTZ)result).dateValue().getTime()); }else{ return result; } } }
import com.alibaba.fastjson.serializer.ClobSeriliazer;
import com.itc.lib.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import oracle.jdbc.OraclePreparedStatement;
import oracle.sql.BLOB;
import oracle.sql.CLOB;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.context.annotation.Configuration;
import javax.sql.rowset.serial.SerialClob;
import java.io.IOException;
import java.io.Writer;
import java.sql.*;

//這個註解定義的是JdbcType型別,這裡的型別不可自己隨意定義,必須要是列舉類org.apache.ibatis.type.JdbcType所列舉的資料型別
@MappedJdbcTypes({JdbcType.CLOB,JdbcType.BLOB  })
//這裡定義的是JavaType的資料型別,描述了哪些Java型別可被攔截
@MappedTypes({String.class})
@Slf4j
@Component
public class TypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { try{ BLOB blob = BLOB.getEmptyBLOB(); blob.setBytes(parameter.getBytes()); ps.setBlob(i,blob); }catch (Exception e){ log.error(e.getMessage(),e); } } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { if (rs.wasNull()) return null; //解決增加異常,這樣做是因為直接放入時操作的是原素組,導致不能增刪操作,所以要重新建立一個 try{ Clob clob = rs.getClob(columnName); return clob == null ? "" : clob.getSubString(1, (int) clob.length()); }catch (Exception e){ Blob blob = rs.getBlob(columnName); return blob == null ? "" : new String(blob.getBytes(1, (int) blob.length())); } } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { if (rs.wasNull()) return null; //解決增加異常,這樣做是因為直接放入時操作的是原素組,導致不能增刪操作,所以要重新建立一個 if("oracle.jdbc.OracleClob".equals(rs.getMetaData().getColumnClassName(columnIndex))){ Clob clob = rs.getClob(columnIndex); return clob == null ? "" : clob.getSubString(1, (int) clob.length()); }else { //if("oracle.jdbc.OracleBlob".equals(rs.getMetaData().getColumnClassName(columnIndex))) Blob blob = rs.getBlob(columnIndex); return blob == null ? "" : new String(blob.getBytes(1, (int) blob.length())); } } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { if (cs.wasNull()) return null; //解決增加異常,這樣做是因為直接放入時操作的是原素組,導致不能增刪操作,所以要重新建立一個 if("oracle.jdbc.OracleClob".equals(cs.getMetaData().getColumnClassName(columnIndex))){ Clob clob = cs.getClob(columnIndex); return clob == null ? "" : clob.getSubString(1, (int) clob.length()); }else { //if("oracle.jdbc.OracleBlob".equals(rs.getMetaData().getColumnClassName(columnIndex))) Blob blob = cs.getBlob(columnIndex); return blob == null ? "" : new String(blob.getBytes(1, (int) blob.length())); } } }

在欄位上使用生效:

@TableField(value = "XXX", typeHandler = TypeHandler.class)

或者(未新增@Component註解時可以生效):

在bootstrap.properties中新增:

mybatis-plus.type-handlers-package=com.xxx.typehandler(com.xxx.typehandler是l包名)