模板方法模式的应用之 MyBatis BaseTypeHandler
在 MyBatis 中,TypeHandler 接口用来给 PreparedStatement 设置参数,以及从 ResultSet 获取结果:
public interface TypeHandler<T> {
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
TypeHandlerRegistry 中注册了很多类型处理器,比如 StringTypeHandler、IntegerTypeHandler 等:
public final class TypeHandlerRegistry {
// ...
public TypeHandlerRegistry() {
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
// ...
}
// ...
}
这些类型处理器都继承自 BaseTypeHandler,BaseTypeHandler 实现了 TypeHandler 接口中的方法,但是仅定义了通用的步骤,具体的实现由子类完成:
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
protected Configuration configuration;
public void setConfiguration(Configuration c) {
this.configuration = c;
}
@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
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 e) {
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: " + e, e);
}
} else {
try {
// ⭐ 设置非 null 参数(子类实现)
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
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: " + e, e);
}
}
}
@Override
public T getResult(ResultSet rs, String columnName) throws SQLException {
T result;
try {
// ⭐ 获取非 null 结果(子类实现)
result = getNullableResult(rs, columnName);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e);
}
if (rs.wasNull()) {
return null;
} else {
return result;
}
}
// ...
/**
* ⭐ 设置非 null 参数(子类实现)
*/
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
/**
* ⭐ 获取非 null 结果(子类实现)
*/
public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
// ...
}
比如 StringTypeHandler 类继承了 BaseTypeHandler 类,并实现了 getNullableResult() 等方法:
public class StringTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getString(columnName);
}
// ...
}
这样做的好处是各种类型的 TypeHandler 都可以通过继承 BaseTypeHandler 类来实现自己的处理逻辑,同时又复用 BaseTypeHandler 类中通用的步骤,既易于扩展,又易于维护。
浙公网安备 33010602011771号