持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 25 天,点击查看活动详情
上期课程中,完成 query() 方法中前三步,这三步分别是注册驱动并获取连接、获取 SQL 语句以及获取预处理对象 prepareStatement。在本期课程实现参数设置,这个参数其实就是 query() 方法中可变参数 params。
这个 params 参数是由谁传递的呢?其实这个参数的传递是由使用自定义持久层框架的使用端再去调用 SqlSession 接口中的方法时,传递的一个参数。
例如,在使用端测试方法中调用 selectOne 方法,传递一个 user 对象。在 query() 方法中,可变参数它实际就是传递过来的 user 对象。那么,要取出 user 对象里面的属性值来为占位符进行赋值,但问题来了,我们怎么知道要取这个 user 对象里面的哪些属性值来为占位符赋值呢?
目前想要解决这个问题怎么办呢?此时,上期课程中解析出 SQL 语句中 #{} 里面的这个参数名称就要起作用了,我们可以根据这个参数名称来确定要获取 user 对象里面的哪个属性值来给这个占位符进行赋值。
如果是按照思路,我们首先是不是要获取到这个 #{} 里面的值,这个值在转换 SQL 语句的时候,已经被解析存取存储到 BoundSql 实体对象上的 List 集合中。
获取集合中数据
通过 boundSql.getParameterMappingList() 获取解析 SQL 语句中 #{} 里面的参数名称。
使用 for 循环遍历集合,遍历的算法使用普通 for 循环,使用这种普通遍历方式原因是需要获取下标 i 的值。
我们 #{} 里面具体的这个参数名称是被封装在 ParameterMapping 这个对象中。我们如何取出这个对象中参数名称呢?首先先取出集合中每一个参数名称,然后在取出具体参数名称。
取到具体参数名称之后,我们将使用反射技术,根据 content 参数名称来获取到实体对象中的一个属性值。然后我们再根据这个属性值来获取到当前user 实体参数里面具体的这个属性值,拿到这个属性值之后,借助 来完成参数设置。
首先获取实体的全路径,只有获取到实体的全路径,才能够去使用反射获取到它的 class 对象,从而获取到它的一个属性对象。
具体代码实现如下所示:
public class SimpleExecutor implements Executor {
@Override
public <E> List<E> query(Configuration configuration, MapperStatement mapperStatement, Object... params) throws Exception {
//...
// 4.设置参数
String parameterType = mapperStatement.getParameterType();
Class<?> parameterTypeClass=getClassType(parameterType);
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
for (int i = 0; i < parameterMappingList.size(); i++){
//取出每一个List集合中参数
ParameterMapping parameterMapping = parameterMappingList.get(0);
//获取 List 集合中具体参数名称
String content = parameterMapping.getContent();
//反射
Field declaredField = parameterTypeClass.getDeclaredField(content);
//设置暴力访问
declaredField.setAccessible(true);
Object o = declaredField.get(params[0]);
preparedStatement.setObject(i+1,o);
}
//...
return null;
}
private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
if(parameterType!=null){
Class<?> aClass = Class.forName(parameterType);
return aClass;
}
return null;
}
//...
}