MyBatis 将一个 Java 对象作为输入参数执行 INSERT 语句操作时,它会创建一个 PreparedStatement 对象,并且 使用 setXXX()方式对占位符设置相应的参数值,当从 SQL 结果集构 建 JavaBean 时,也有类似的过程。

MyBatis 对于以下的类型使用内建的类型处理器:所有的基本数据类型、基本类型的包装类型、byte[]java.util.Datejava.sql.Datejava,sql.Timejava.sql.TimestampEnum类型等。对于自定义类型,持久化和查询则可创建自定义typeHandlers类型处理器。

typeHandlers原理

对于如下mapper

<insert id="insertStudent" parameterType="Student">
    INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,BIRTH)
    VALUES(#{studId},#{name},#{email},#{birth})
</insert>

执行预处理

PreparedStatement pstmt = connection.prepareStatement
                    ("INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,birth) VALUES(?,?,?,?)")

通过使用类型处理器typeHandlers设置参数,对于java.util.Date 类型转会换为 java.sql.Timestamp 设值(见:DateTypeHandler)。

pstmt.setInt(1,student.getStudId());
pstmt.setString(2, student.getName());
pstmt.setString(3, student.getEmail());
pstmt.setTimestamp(4, new Timestamp(student.getBirth().getTime()));

自定义typeHandlers

对于如下自定义枚举类型则需要新建typeHandlers

public enum ThirdPartyLogType {
	ITEM(0, "商品"), TRADE(1, "订单"), SUPPLIER(2, "供应商");

	private int type;
	private String name;

	ThirdPartyLogType(int type, String name) {
		this.type = type;
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}

	public static ThirdPartyLogType valuesOf(int type) {
		for (ThirdPartyLogType thirdPartyLogType : ThirdPartyLogType.values()) {
			if (thirdPartyLogType.getType() == type) {
				return thirdPartyLogType;
			}
		}
		return null;
	}
}

ThirdPartyLogTypeTypeHandler如下:

@MappedTypes(ThirdPartyLogType.class)
public class ThirdPartyLogTypeTypeHandler extends EnumTypeHandler<ThirdPartyLogType> {
    public ThirdPartyLogTypeTypeHandler(Class<ThirdPartyLogType> type) {
        super(type);
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, ThirdPartyLogType parameter, JdbcType jdbcType) throws SQLException {
        if (jdbcType == null) {
            ps.setInt(i, parameter.getType());
        } else {
            ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE);
        }
    }

    @Override
    public ThirdPartyLogType getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int s = rs.getInt(columnName);
        return ThirdPartyLogType.valuesOf(s);
    }

    @Override
    public ThirdPartyLogType getNullableResult(ResultSet rs, int columnIndex) throws SQLException{
        int s = rs.getInt(columnIndex);
        return ThirdPartyLogType.valuesOf(s);
    }

    @Override
    public ThirdPartyLogType getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int s = cs.getInt(columnIndex);
        return ThirdPartyLogType.valuesOf(s);
    }
}   

注册typeHandlers

对于自定义typeHandlers需要注册,可以使用SqlSessionFactory中的typeHandlersPackagetypeHandlers进行注册

   <bean id="sqlSessionFactory" class="org.mybatis.HgjSqlSessionFactoryBean">
        <property name="mapperLocations" value="classpath*:org/dinozhang/**/dao/xml/**/*.xml"></property>
        <property name="dataSource" ref="dataSource" />
        <property name="typeHandlersPackage" value="org.dinozhang.typehandler"/>
   </bean>