1. 程式人生 > >MyBatis初窺:自定義TypeHandler處理列舉

MyBatis初窺:自定義TypeHandler處理列舉

TypeHandler簡介

在MyBatis中,StatementHandler負責對需要執行的SQL語句進行預編譯處理,主要完成以下兩項工作:
1.呼叫引數處理器(ParameterHandler)來設定需要傳入SQL的引數;
2.呼叫結果集處理器(ResultSetHandler)來處理查詢到的結果資料;
而不管要完成其中的哪一項工作都需要使用型別處理器(TypeHandler)來進行資料型別處理,無論是ParameterHandler為預處理語句(PreparedStatement)設定一個引數,還是ResultSetHandler將結果集中的一條記錄轉換為合適的Java型別。在整個過程中,TypeHandler
負責完成資料庫型別與JavaBean型別的轉換工作。

自定義列舉型別處理器

以列舉型別的處理器為例,MyBatis提供了EnumTypeHandlerEnumOrdinalTypeHandler兩個處理器來處理列舉型別。這兩個處理器之間的區別在於EnumTypeHandler是將列舉的name值存到資料庫,而EnumOrdinalTypeHandler會將列舉的序號值(>=0)存入資料庫。
當然,我們還可以自己寫一個TypeHandler來控制在設定引數或者取出結果集時應該如何對引數型別進行轉換或封裝。
自定義一個TypeHandler需要以下幾個步驟:
1.實現TypeHandler介面或者繼承BaseTypeHandler

2.使用@MappedTypes(value = {})定義需要由該處理器處理的java型別。
  使用@MappedJdbcTypes(value = {})定義所對應的jdbcType型別。
3.在自定義結果集標籤或者引數處理的時候宣告使用自定義TypeHandler進行處理或者在全域性配置TypeHandler要處理的javaType
以下是自定義的列舉型別處理器的原始碼。

EnumTypeHandler類

package org.mybatis.typehandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

/**
 * mapper裡欄位到列舉類的對映。
 * 用法一: 
 * 	儲存到資料庫:#{enumDataField,typeHandler=com.mybatis.typehandler.EnumTypeHandler} 
 *  從資料庫查出:
 *   <resultMap> <result property="enumDataField" column="enum_data_field"
 *   javaType="com.xxx.MyEnum"
 *   typeHandler="com.mybatis.typehandler.EnumTypeHandler"/>
 *   </resultMap>
 *
 * 用法二: 
 *  1)在mybatis-config.xml中指定handler: 
 *   <typeHandlers> 
 *   <typeHandler handler="com.mybatis.typehandler.EnumTypeHandler" javaType="com.xxx.MyEnum"/> 
 *   </typeHandlers>
 *  2)在MyClassMapper.xml裡直接select/update/insert。
 */

public class EnumTypeHandler<E extends Enum<?> & CodeBaseEnum> extends
		BaseTypeHandler<CodeBaseEnum> {
	private Class<E> clazz;

	public EnumTypeHandler(Class<E> enumType) {
		if (enumType == null)
			throw new IllegalArgumentException("Type argument cannot be null");

		this.clazz = enumType;
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i,
			CodeBaseEnum parameter, JdbcType jdbcType) throws SQLException {
		ps.setInt(i, parameter.code());
	}

	@Override
	public E getNullableResult(ResultSet rs, String columnName)
			throws SQLException {
		return CodeEnumUtil.codeOf(clazz, rs.getInt(columnName));
	}

	@Override
	public E getNullableResult(ResultSet rs, int columnIndex)
			throws SQLException {
		return CodeEnumUtil.codeOf(clazz, rs.getInt(columnIndex));
	}

	@Override
	public E getNullableResult(CallableStatement cs, int columnIndex)
			throws SQLException {
		return CodeEnumUtil.codeOf(clazz, cs.getInt(columnIndex));
	}
}

CodeBaseEnum類

package org.mybatis.typehandler;

public interface CodeBaseEnum {
	int code();
}

CodeEnumUtil類

package org.mybatis.typehandler;

public class CodeEnumUtil {
	/**
	 * @param enumClass
	 * @param code
	 * @param <E>
	 * @return
	 */
	public static <E extends Enum<?> & CodeBaseEnum> E codeOf(
			Class<E> enumClass, int code) {
		E[] enumConstants = enumClass.getEnumConstants();
		for (E e : enumConstants) {
			if (e.code() == code)
				return e;
		}
		return null;
	}
}

測試Gender類

package org.mybatis.entity;

import org.mybatis.typehandler.CodeBaseEnum;

public enum Gender implements CodeBaseEnum {

	MALE(0, "男"), FEMALE(1, "女");
	private Integer code;
	private String msg;

	Gender(Integer code, String msg) {
		this.code = code;
		this.msg = msg;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	@Override
	public int code() {
		return code;
	}

}