beetlsql对外暴露最重要的类是SQLManager,SQLmanager里有很多实用的方法。
但是Sqlmnager并不是真正流程的执行者,而是SQLScript这个类。这个类里面都是执行细节。
我们这次只挑出其select行为的最终方法List
如下所示:
public List select(Class clazz, Map paras, RowMapper mapper) {
//检查是否modele类上是否有带有@Builder的注解,如果有的话,执行一下before
checkAnnotatonBeforeSelect(clazz, paras);
//运行sql模板,获取实际的sql语句
SQLResult result = run(paras);
String sql = result.jdbcSql;
List objs = result.jdbcPara;
ResultSet rs = null;
PreparedStatement ps = null;
List resultList = null;
//执行Interceptor的before
InterceptorContext ctx = this.callInterceptorAsBefore(this.id, sql, false, objs, paras);
//如果Interceptor的before有返回值,那么就直接返回,然后执行Interceptor的after
if (ctx.getResult() != null) {
this.callInterceptorAsAfter(ctx, ctx.getResult());
return (List) ctx.getResult();
}
//再次获取参数,因为有可能被改变
sql = ctx.getSql();
objs = ctx.getParas();
Connection conn = null;
try {
conn = sm.getDs().getConn(id, false, sql, objs);
ps = conn.prepareStatement(sql);
this.setPreparedStatementPara(ps, objs);
rs = ps.executeQuery();
//检查是否有RowMapper,如果有自定义RowMapper,那么按照Rowmapper进行分行解析
if (mapper != null) {
BeanProcessor beanProcessor = this.getBeanProcessor();
resultList = new RowMapperResultSetExt(mapper, beanProcessor).handleResultSet(this.id,rs, clazz);
} else {
//按照正常解析
resultList = mappingSelect(rs, clazz);
}
//执行Interceptor的after
this.callInterceptorAsAfter(ctx, resultList);
//检查是否modele类上是否有带有@Builder的注解,如果有的话,执行一下after
resultList = this.checkAnnotatonAfterSelect(clazz, resultList, result);
//sql 脚本里通过listener 实现最后处理,这个目前只有orm.single等
if (this.getListener() != null) {
for (SQLResultListener listener : getListener()) {
listener.dataSelectd(resultList,paras,this.sm,result);
}
}
return resultList;
} catch (SQLException e) {
this.callInterceptorAsException(ctx, e);
throw new BeetlSQLException(BeetlSQLException.SQL_EXCEPTION, e);
} finally {
clean(false, conn, ps, rs);
}
}
通过这段代码,可以了解到beetlsql的select流程如下:
- Builder.before
- Interceptor.before
- query数据库
- 解析statement数据,有Rowmapper按Rowmapper,没有按mappingSelect(rs, clazz);
- Interceptor.before
- Builder.after
- Listener
那么在一般情况下,我们没有新建builder/interceptor/mapper/listener
所以只会执行第4条的mappingSelect
之所以要看这个结构,主要还是对于一些高级应用,要看插入自定义的一些组件的时机。
对一些组件的解释:
builder:
官方有个@Builder的注解,该注解是针对自定义注解的。如果你写一个注解,上面再盖上@Builder,然后将这个注解放到model类上或者model的属性上就可以被检索到。
当然@Builder里是有值的,比如ObjectSelectBuilder,这是针对查询的接口,你还需要新建个子类实现它。
具体的还是深入上面代码的第一行checkAnnotatonBeforeSelect里有个cache.init()里就了解了。
interceptor:
这是个拦截器,有查询的前置拦截和后置拦截。用处我没有仔细看,但可以更改sql语句,比如,你可以写个拦截器,思路如下:
根据方法名,如果带有ByPage的后缀且xx的参数,那么就加上limit xx.......
Rowmapper:
这个是行解析器。注意,是行解析器。
也就是说,你查询表,查询到了10行数据,这个会for循环10行,抛出每一行留给你自己去自定义封装。
其实这个有点过度设计了。一点用没有。
作者实际上应该抛出所有数据让用户自定义封装。
listener:
目前都是用于@orm.single等orm
使用了线程的数据传递holder。当然肯定可以后续扩展。
接下来看第4条的mappingSelect方法。
@SuppressWarnings("unchecked")
public List mappingSelect(ResultSet rs, Class clazz) throws SQLException {
List resultList = null;
BeanProcessor beanProcessor = this.getBeanProcessor();
//类型判断需要做性能优化
if (Map.class.isAssignableFrom(clazz)) {
// 如果是Map的子类或者父类,返回List
这段代码简单的说是这样的,
取出默认的BeanProcessor,对封装结果的类型进行检查。
如果是map,则走 beanProcessor.toMap
如果是基本数据类型如Int,boolean,String等,则走beanProcessor.toBaseType
其他的就走 beanProcessor.toBeanList方法。
很明显,对于绝大部分查询都会走beanProcessor.toBeanList方法的。
这是个很有意思的事情,BeanProcessor是可以自定义的,通过SQLManager.getProcessors得到了一个HashMap