在JDBC中,需要在PreparedStatement对象中设置那些已经预编译过的SQL语句 参数。 执行SQL后,会通过ResultSet对象获取得到数据库的数据,而这些MyBatis是根据数据的类型通过typeHandler来实现的。
在typeHandler中,分为jdbcType和javaType,其中jdbcType用于定义数据库类型,javaType用于定义Java类型,那么typeHandler的作用就是承担jdbcType和javaType之间的相互转换。
在MyBatis中存在系统定义的typeHandler和自定义的typeHandler。MyBatis会根据javaType和数据库的jdbcType决定采用哪个typeHandler处于这些转换规则。
系统提供的typeHandler能覆盖大部分场景的要求,但是有些情况下是不够的,比如我们有特殊的转换规则,枚举类就是这样。
MyBatis内部定义了许多有用的typeHandler,这里列举一些
类型处理器 | Java类型 | JDBC类型 |
---|---|---|
IntegerTypeHandler | java.lang.Integer,int | 数据库兼容的NUMERIC或SHORT INTEGER |
StringTypeHandler | java.lang.String | CHAR、VARCHAR |
在MyBatis中typeHandler都要实现接口org.pe.TypeHandler。
// T是泛型,专指javaType
public interface TypeHandler<T> {// 通过PreparedStatement 对象进行设置SQL参数 // i是参数在SQL的下标// parameter是参数// jdbcType是数据库类型void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;// 从JDBC结果集中获取数据进行转换,要么使用列名(columnName)要么使用下标(columnIndex)获取数据库的数据T getResult(ResultSet var1, String var2) throws SQLException;T getResult(ResultSet var1, int var2) throws SQLException;// 存储过程专用的T getResult(CallableStatement var1, int var2) throws SQLException;
}
我们这里以StringTypeHandler
为例,研究一下MyBatis系统的typeHandler是如何实现的。
查看StringTypeHandler的源码,可以发现它继承了BaseTypeHandler
// BaseTypeHandler本身是一个抽象类,需要子类去实现其定义的4个抽象方法,而它本身实现了typeHandler接口的4个方法
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {// 当parameter和jdbcType同时为空,MyBatis将抛出异常if (parameter == null) {if (jdbcType == null) {throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");}try {ps.setNull(i, jdbcType.TYPE_CODE);} catch (SQLException var7) {throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + var7, var7);}} else { try {// 设置参数this.setNonNullParameter(ps, i, parameter, jdbcType);} catch (Exception var6) {throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different configuration property. " + "Cause: " + var6, var6);}}}public T getResult(ResultSet rs, String columnName) throws SQLException {Object result;try {// 返回非空结果集result = NullableResult(rs, columnName);} catch (Exception var5) {throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + var5, var5);}return rs.wasNull() ? null : result;}public T getResult(ResultSet rs, int columnIndex) throws SQLException {Object result;try {result = NullableResult(rs, columnIndex);} catch (Exception var5) {throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set. Cause: " + var5, var5);}return rs.wasNull() ? null : result;}public T getResult(CallableStatement cs, int columnIndex) throws SQLException {Object result;try {result = NullableResult(cs, columnIndex);} catch (Exception var5) {throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement. Cause: " + var5, var5);}return cs.wasNull() ? null : result;}public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException;public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException;public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}
接下来再看
public class StringTypeHandler extends BaseTypeHandler<String> {public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, parameter);}public String getNullableResult(ResultSet rs, String columnName) throws SQLException {String(columnName);}public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String(columnIndex);}public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String(columnIndex);}
}
在这里MyBatis就把javaType和jdbcType进行了相互转换。
那么它们是如何注册的?
是通过org.pe.TypeHandlerRegistry
类对象的register
方法进行注册
public TypeHandlerRegistry() {ister((Class)Boolean.class, (TypeHandler)(new BooleanTypeHandler()));ister((Class)Boolean.TYPE, (TypeHandler)(new BooleanTypeHandler()));...
}
这样就实现了自带的typeHanlder注册。
自定义的typeHandler一般不会使用代码注册,而是通过配置或扫描
这里我们仿造一个StringTypeHandler
/*** 自定义的typeHandler 实现StringTypeHandler的功能* @author Why**/
public class MyTypeHandler implements TypeHandler<String>{Logger logger = Logger(MyTypeHandler.class);@Overridepublic String getResult(ResultSet rs, String columnName) throws SQLException {String result = rs.getString(columnName);logger.info("读取string参数1【" + result +"】");return result;}@Overridepublic String getResult(ResultSet rs, int columnIndex) throws SQLException {String result = rs.getString(columnIndex);logger.info("读取string参数2【" + result +"】");return result;}@Overridepublic String getResult(CallableStatement cs, int columnIndex) throws SQLException {String result = cs.getString(columnIndex);logger.info("读取string参数3【" + result +"】");return result;}@Overridepublic void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {logger.info("设置string参数【" + parameter + "】");ps.setString(i, parameter);}
}
在完成了typeHandler的自定义之后,我们还需要配置扫描
<typeHandlers><typeHandler handler="peHandler.MyTypeHandler" jdbcType="VARCHAR" javaType="string"/>
</typeHandlers>
最后就是自定义typeHandler的使用了
<mapper namespace="com.whyalwaysmea.mapper.RoleMapperWithTypeHandler"> <resultMap type="role" id="roleMapper"><result property="id" column="id"/><result property="roleName" column="role_name" jdbcType="VARCHAR" javaType="string"/><result property="note" column="note" typeHandler="peHandler.MyTypeHandler"/></resultMap><select id="findRoles1" parameterType="string" resultType="role">select id, role_name, note from t_role where role_name like concat('%', #{roleName, jdbcType=VARCHAR, javaType=string}, '%')</select><select id="findRoles2" parameterType="string" resultType="role">select id, role_name, note from t_role where role_name like concat('%', #{roleName, typeHandler=peHandler.MyTypeHandler}, '%')</select>
</mapper>
这里展示两种使用自定义typeHandler的方式:
有时候配置的typeHandler太多,也可以使用包扫描的方式
<typeHandlers> <package name="peHandler"/>
</typeHandlers>
这样还需要处理一下自定义的typeHandler类,指定jdbcType和javaType
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(String.class)
public class MyTypeHandler implements TypeHandler<String>{...
}
本文发布于:2024-02-01 07:24:32,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170674347234868.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |