beetlSql的源码解析

beetlsql对外暴露最重要的类是SQLManager,SQLmanager里有很多实用的方法。

但是Sqlmnager并不是真正流程的执行者,而是SQLScript这个类。这个类里面都是执行细节。

我们这次只挑出其select行为的最终方法List<T> select(Class<T> clazz, Map<String, Object> paras, RowMapper<T> mapper)

如下所示:

public <T> List<T> select(Class<T> clazz, Map<String, Object> paras, RowMapper<T> mapper) {
        //检查是否modele类上是否有带有@Builder的注解,如果有的话,执行一下before
        checkAnnotatonBeforeSelect(clazz, paras);
        //运行sql模板,获取实际的sql语句
        SQLResult result = run(paras);
        String sql = result.jdbcSql;
        List<SQLParameter> objs = result.jdbcPara;
        ResultSet rs = null;
        PreparedStatement ps = null;
        List<T> 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<T>) 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<T>(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流程如下:

  1. Builder.before
  2. Interceptor.before
  3. query数据库
  4. 解析statement数据,有Rowmapper按Rowmapper,没有按mappingSelect(rs, clazz);
  5. Interceptor.before
  6. Builder.after
  7. 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 <T> List<T> mappingSelect(ResultSet rs, Class<T> clazz) throws SQLException {
        List<T> resultList = null;
        BeanProcessor beanProcessor = this.getBeanProcessor();
        //类型判断需要做性能优化
        if (Map.class.isAssignableFrom(clazz)) {
            // 如果是Map的子类或者父类,返回List<Map<String,Object>>
            resultList = new ArrayList<T>();
            while (rs.next()) {

                Map map = beanProcessor.toMap(this.sqlSource.getId(), clazz, rs);
                resultList.add((T) map);
            }
            return resultList;

        } else if (isBaseDataType(clazz)) {

            resultList = new ArrayList<T>(1);

            while (rs.next()) {
                Object result = beanProcessor.toBaseType(this.sqlSource.getId(), clazz, rs);
                resultList.add((T) result);
            }
        } else {
            resultList = beanProcessor.toBeanList(this.sqlSource.getId(), rs, clazz);
            return resultList;
        }

        return resultList;

    }

这段代码简单的说是这样的,

取出默认的BeanProcessor,对封装结果的类型进行检查。

如果是map,则走 beanProcessor.toMap

如果是基本数据类型如Int,boolean,String等,则走beanProcessor.toBaseType

其他的就走 beanProcessor.toBeanList方法。

很明显,对于绝大部分查询都会走beanProcessor.toBeanList方法的。

这是个很有意思的事情,BeanProcessor是可以自定义的,通过SQLManager.getProcessors得到了一个HashMap<sqlid,BeanProcessor>,你可以在初始化的时候塞入一个自定义的BeanProcessor截断源码的结果集解析。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章