模板方法模式的应用之 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 类中通用的步骤,既易于扩展,又易于维护。

posted @   Higurashi-kagome  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示