有两种情况
-
一个参数,默认不作任何的处理,除非设置了@param注解,会用唯一的参数与占位符进行对应(占位符随便写什么都行)
-
多个参数(转化成Map,基于key进行映射)
-
通过顺序方式,转化成param1,param2…作为key,value为传进来的值
-
加上param注解,可以自定义key,取代生成的arg0。。。
-
基于反射获取变量名称,JDK1.8才支持,如果不支持转换成arg0、arg1。。等
-
为一个JavaBean时,也会映射一个Map出来
参数转化的操作位于ParamNameResolver中的getNamedParams方法里
而PrepareStatementHandler为一个接口,而且对应的实现类只有一个DefaultParameterHandler(所以,一定会经过DefaultParameterHandler)
这里要注意的一点是,这里的处理并不是经过动态代理的!动态代理是在SqlSession前去做的(以后再讲动态代理层面上)
可以参考下面的执行情况(可以看到动态代理过程在最前面的,即只有一层动态代理)
下面还是回归看,怎么去填充参数的吧
DefaultParameterHandler
这个是唯一的ParameterHandler实现类,所以参数处理都是交给他去做的,处理参数的方法为setParameter,下面是源码
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity(“setting parameters”).object(mappedStatement.getParameterMap().getId());
//此时boundSql封装了sql、输入的参数、sql参数的映射
//这里是获取sql参数的映射(不包括值)
List parameterMappings = boundSql.getParameterMappings();
//如果参数的映射不为空,也就是(一般不会为空,顶多size为0)
//当sql里面没有参数,比如select all 就没有这些参数的映射了
//此时parameterMappings就会为size = 0
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
//获取每一个参数映射
ParameterMapping parameterMapping = parameterMappings.get(i);
//如果参数映射的类型不为OUT
//参数映射的类型有IN OUT INOUT三种
//如果为OUT是不做处理的
if (parameterMapping.getMode() != ParameterMode.OUT) {
//这个value是用来存储额外的参数的,其实就是sql参数对应传进去的值!
Object value;
//获取映射的名称,如果没有加param注解且多个参数,就是arg0,arg1。。那些
String propertyName = parameterMapping.getProperty();
//判断当前这个映射的参数有没有额外参数
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
}
//判断parameterObject是否为空
//parameterObject是用来存储映射关系的,也就是sql参数与传进来的参数映射
//比如arg0~123
//也就是如果没有传进来的参数,那么额外参数value也为null
else if (parameterObject == null) {
value = null;
}
//TypeHandler为类型处理器,也就是用来转化JavaBean和SQL列数组映射的
//这里是针对只有一个参数的时候
//只有一个参数的时候,parameterObject不是一个Map,而是一个引用类型
//这时候就会注册相对应的处理器了(没有Map的处理器)
else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
}
//一般来说都是else这里进行处理
else {
//获取parameter的元数据
MetaObject metaObject = configuration.newMetaObject(parameterObject);
//从元数据中去获取该sql参数对应的值!
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
value = metaObject.getValue(propertyName);
}
//获取这个映射参数的类型处理器
//在parameterMapping中有已经固定了类型处理器
TypeHandler typeHandler = parameterMapping.getTypeHandler();
//同时去获取jdbc的类型
JdbcType jdbcType = parameterMapping.getJdbcType();
//如果没有设置jdbc连接类型且映射Sql参数的值为null
//不太懂。。。
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
//交由typeHandler去进行转化参数
//也就是由Java类型去转化成sql类型
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
从代码上可以看到