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截斷源碼的結果集解析。

 

 

 

 

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