网站首页 > 技术文章 正文
1.ParameterMapping的作用
ParameterHandler给PrepareStatement传递参数时,是从ParameterMapping获取参数值,然后通过下标方式给PrepareStatement设置参数
2.ParameterMapping创建过程
从DefaultParameterHandler的setParameters方法中,可以知道ParameterMapping是从BoundSql中通过getParameterMappings得到ParameterMapping的集合
BoundSql是通过SqlSourceBuilder调用parse方法解析sql时创建的,在方法中可以看到创建StaticSqlSource时会获取handler的ParameterMappings赋值给BoundSql
那么继续查看SqlSourceBuilder.ParameterMappingTokenHandler中是怎么创建ParameterMappings的
在SqlSourceBuilder的parse方法中,会创建一个SqlSourceBuilder.ParameterMappingTokenHandler对象和GenericTokenParser对象,而解析过程实际是调用GenericTokenParser的parse方法实现
GenericTokenParser的parse方法中会截取openToken和closeToken之间的字符放入expression中,然后调用handler的handleToken方法进行处理
GenericTokenParser初始化时传入的openToken和closeToken分别为“#{” 和 “}”,handler是SqlSourceBuilder.ParameterMappingTokenHandler的实例
SqlSourceBuilder.ParameterMappingTokenHandler的handleToken方法中将sql中#{}里面字符串通过buildParameterMapping方法处理后获得ParameterMapping对象,然后访入parameterMappings的集合中
而实际sql则用"?"替代原来的#{},进而可以通过PrepareStatement进行参数传递
在ParameterMappingTokenHandler的buildParameterMapping方法中,传入参数的名称,返回ParameterMapping对象
public class SqlSourceBuilder extends BaseBuilder {
private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
private ParameterMapping buildParameterMapping(String content) {
//将字符串解析为map类型
Map<String, String> propertiesMap = this.parseParameterMapping(content);
//从解析的Map中获取property的值
String property = (String)propertiesMap.get("property");
//获取propertyType的类对象
Class propertyType;
//1.从ObjectFactory中获取
if (this.metaParameters.hasGetter(property)) {
propertyType = this.metaParameters.getGetterType(property);
//2.根据TypeHandler获取
} else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterType)) {
propertyType = this.parameterType;
//3.JdbcType.CURSOR处理
} else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
propertyType = ResultSet.class;
//4.Map形式参数处理
} else if (property != null && !Map.class.isAssignableFrom(this.parameterType)) {
MetaClass metaClass = MetaClass.forClass(this.parameterType, this.configuration.getReflectorFactory());
if (metaClass.hasGetter(property)) {
propertyType = metaClass.getGetterType(property);
} else {
propertyType = Object.class;
}
} else {
//4.如果shangr情况不满足,则默认为Object对象
propertyType = Object.class;
}
//根据Property和PropertyType创建Builder对象
Builder builder = new Builder(this.configuration, property, propertyType);
Class<?> javaType = propertyType;
String typeHandlerAlias = null;
Iterator var8 = propertiesMap.entrySet().iterator();
//遍历上述的Map,根据值的类型给builder属性赋值
while(var8.hasNext()) {
Entry<String, String> entry = (Entry)var8.next();
String name = (String)entry.getKey();
String value = (String)entry.getValue();
if ("javaType".equals(name)) {
javaType = this.resolveClass(value);
builder.javaType(javaType);
} else if ("jdbcType".equals(name)) {
builder.jdbcType(this.resolveJdbcType(value));
} else if ("mode".equals(name)) {
builder.mode(this.resolveParameterMode(value));
} else if ("numericScale".equals(name)) {
builder.numericScale(Integer.valueOf(value));
} else if ("resultMap".equals(name)) {
builder.resultMapId(value);
} else if ("typeHandler".equals(name)) {
typeHandlerAlias = value;
} else if ("jdbcTypeName".equals(name)) {
builder.jdbcTypeName(value);
} else if (!"property".equals(name)) {
if ("expression".equals(name)) {
throw new BuilderException("Expression based parameters are not supported yet");
}
throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName");
}
}
if (typeHandlerAlias != null) {
builder.typeHandler(this.resolveTypeHandler(javaType, typeHandlerAlias));
}
//通过Builder创建ParameterMapping
return builder.build();
}
}
}
2.1.将字符串解析为Map类型
ParameterMappingTokenHandler的parseParameterMapping方法中创建一个ParameterExpression对象,传入#{}中的字符串
public class SqlSourceBuilder extends BaseBuilder {
private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
private Map<String, String> parseParameterMapping(String content) {
try {
return new ParameterExpression(content);
} catch (BuilderException var3) {
throw var3;
} catch (Exception var4) {
throw new BuilderException("Parsing error was found in mapping #{" + content + "}. Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", var4);
}
}
}
}
ParameterExpression继承与HashMap,主要是对字符串的处理,它会将字符串以“,”逗号和冒号分隔,第一个字符串以property属性存放,后面的字符串以“=”分隔,将=号前后的字符串以key-value的形式存放
如果属性后面接的是“:”冒号,则默认为jdbcType属性,不需要显示的填写jdbcType字符了
2.2.通过Builder创建ParameterMapping
然后根据配置获取各个属性的值,并赋值给builder,注意只能是以下这些类型“javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName”,否则会报错
如果配置了TypeHandler,则会根据javaType和TypeHandler去获取TypeHandler类并赋值,就是到typeHandlerRegistry中获取
最后调用Builder的build方法创建ParameterMapping对象,创建是使用了构造者模式,用来解决参数过多不好管理的问题
创建是首先会判断typeHandler是否为空,如果为空,也就是配置文件中没有指定。那么会根据javaType和jdbcType去typeHandlerRegistry中获取对应的TypeHandler
public class ParameterMapping {
public static class Builder {
public ParameterMapping build() {
this.resolveTypeHandler();
this.validate();
return this.parameterMapping;
}
private void validate() {
if (ResultSet.class.equals(this.parameterMapping.javaType)) {
if (this.parameterMapping.resultMapId == null) {
throw new IllegalStateException("Missing resultmap in property '" + this.parameterMapping.property + "'. Parameters of type java.sql.ResultSet require a resultmap.");
}
} else if (this.parameterMapping.typeHandler == null) {
throw new IllegalStateException("Type handler was null on parameter mapping for property '" + this.parameterMapping.property + "'. It was either not specified and/or could not be found for the javaType (" + this.parameterMapping.javaType.getName() + ") : jdbcType (" + this.parameterMapping.jdbcType + ") combination.");
}
}
private void resolveTypeHandler() {
if (this.parameterMapping.typeHandler == null && this.parameterMapping.javaType != null) {
Configuration configuration = this.parameterMapping.configuration;
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(this.parameterMapping.javaType, this.parameterMapping.jdbcType);
}
}
}
}
ParameterMapping中就是保存了参数的相关信息,最为重要的是TypeHandler属性
public class ParameterMapping {
private Configuration configuration;
private String property;
private ParameterMode mode;
private Class<?> javaType;
private JdbcType jdbcType;
private Integer numericScale;
private TypeHandler<?> typeHandler;
private String resultMapId;
private String jdbcTypeName;
private String expression;
}
3.ParameterMapping使用
了解的ParameterMapping的创建过程,继续查看它的使用情况
ParameterMapping使用比较简单,主要是在DefaultParameterMapping中对PrepareStatement设置参数
设置过程:从ParameterMapping中获取property属性,然后从方法入参中获得对应的值,接着从ParameterMapping中获取TypeHandler,最后是通过TypeHandler给PrepareStatement通过下标的方式设置参数
猜你喜欢
- 2024-12-18 Java开发中MongoDB数据库相关操作
- 2024-12-18 HashMap有几种遍历方法?推荐使用哪种?
- 2024-12-18 在RedisTemplate中使用scan代替keys指令
- 2024-12-18 MQ的发布订阅模式(fanout) mq几种消息模式
- 2024-12-18 既然有MySQL了,为什么还要有MongoDB?
- 2024-12-18 Java遍历一个 List 有哪些方式?每种的实现原理以及哪种最高效?
- 2024-12-18 为什么很多人不愿意用hibernate了?
- 2024-12-18 Qt中 QMap 类、QHash 类、QVector 类详解
- 2024-12-18 半小时搞懂 IO 模型 io模型详解
- 2024-12-18 思考:为什么很多人不愿意用hibernate了?
- 1507℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 511℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 487℃MySQL service启动脚本浅析(r12笔记第59天)
- 467℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 465℃启用MySQL查询缓存(mysql8.0查询缓存)
- 445℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 424℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 421℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)