天哪!手动编写mybatis雏形竟然这么简单 (4)

我们可以看到DefaultSqlSeeion 获取到了configuration,并通过statementid 从configuration 中获取mapper。 然后具体实现交给了Executer 类来实现。我们这里先不管Executer 是怎么实现的,就假装已经实现了。那么整个框架端就完成了。通过调用Sqlsession.selectList() 方法,来获取结果。

在这里插入图片描述


感觉我们都还没有处理,就框架搭建好了?骗鬼呢,确实前面我们从获取文件解析文件,然后创建工厂。都是做好准备工作。下面开始我们JDBC的实现。

SqlSession 具体实现

我们前面说SqlSeesion 的具体实现有下面5步
1、获取数据库连接
2、获取sql,并对sql 进行解析
3、通过内省,将参数注入到preparedStatement 中
4、执行sql
5、通过反射将结果集封装成对象

但是我们在DefaultSqlSeeion 中将实现交给了Executer来执行。所以我们就要在Executer中来实现这些操作。

我们首先来创建一个Executer 接口,并写一个DefaultSqlSeeion中调用的query 方法。

public interface Executer { <E> List<E> query(Configuration configuration,Mapper mapper,Object...parm) throws Exception; }

接着我们写一个SimpleExecuter 类来实现Executer 。
然后SimpleExecuter.query()方法中,我们一步一步的实现。

获取数据库连接

因为数据库连接信息保存在configuration,所以直接获取就好了。

//获取连接 connection=configuration.getDataSource().getConnection(); 获取sql,并对sql 进行解析

我们这里想一下,我们在Usermapper.xml写的sql 是什么样子?

select * from user where username=#{username} {username} 这样的sql 我们改怎么解析呢?

分两步
1、将sql 找到#{***},并将这部分替换成 ?号

2、对 #{***} 进行解析获取到里面的参数对应的paramType 中的值。

具体实现用到下面几个类。
GenericTokenParser类,可以看到有三个参数,开始标记,就是我们的“#{” ,结束标记就是 “}”, 标记处理器就是处理标记里面的内容也就是username。

public class GenericTokenParser { private final String openToken; //开始标记 private final String closeToken; //结束标记 private final TokenHandler handler; //标记处理器 public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) { this.openToken = openToken; this.closeToken = closeToken; this.handler = handler; } /** * 解析${}和#{} * @param text * @return * 该方法主要实现了配置文件、脚本等片段中占位符的解析、处理工作,并返回最终需要的数据。 * 其中,解析工作由该方法完成,处理工作是由处理器handler的handleToken()方法来实现 */ public String parse(String text) { //具体实现 } }

主要的就是parse() 方法,用来获取操作1 的sql。获取结果例如:

select * from user where username=?

那上面用到TokenHandler 来处理参数。
ParameterMappingTokenHandler实现TokenHandler的类

public class ParameterMappingTokenHandler implements TokenHandler { private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>(); // context是参数名称 #{id} #{username} @Override public String handleToken(String content) { parameterMappings.add(buildParameterMapping(content)); return "?"; } private ParameterMapping buildParameterMapping(String content) { ParameterMapping parameterMapping = new ParameterMapping(content); return parameterMapping; } public List<ParameterMapping> getParameterMappings() { return parameterMappings; } public void setParameterMappings(List<ParameterMapping> parameterMappings) { this.parameterMappings = parameterMappings; } }

可以看到将参数名称存放 ParameterMapping 的集合中了。
ParameterMapping 类就是一个实体,用来保存参数名称的。

public class ParameterMapping { private String content; public ParameterMapping(String content) { this.content = content; } //getter()和setter() 方法。 }

所以我们在我们通过GenericTokenParser类,就可以获取到解析后的sql,以及参数名称。我们将这些信息封装到BoundSql实体类中。

public class BoundSql { private String sqlText; private List<ParameterMapping> parameterMappingList=new ArrayList<>(); public BoundSql(String sqlText, List<ParameterMapping> parameterMappingList) { this.sqlText = sqlText; this.parameterMappingList = parameterMappingList; } ////getter()和setter() 方法。 }

好了,那么分两步走,先获取,后解析
获取
获取原始sql 很简单,sql 信息就存在mapper 对象中,直接获取就好了。

String sql=mapper.getSql()

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxyxx.html