基于pojo的内存集合数据操作的设计

在一些复杂业务处理场景中,难免碰到一些业务需求:
要根据数据库查询到数据,再进行分类汇总,甚至是和另一部分数据进行关联查询
在这种场景下就需要用到内存集合数据处理器

github地址:https://github.com/eva233man/collection-database

内存集合处理器

  • 内存集合处理器提供基于List集合的仿数据库的查询处理能力,支持select、where、group by、order by以及关联查询。
  • 用于对内存集合数据的轻量级加工,提供统一的API,减轻对物理库的依赖。为后续去O后的类sql处理提供统一的API
  • 数据不做物理存储,不需要再次和数据库交互处理
  • 支持传入类sql语句来执行集合的查询处理,这个查询语言叫做:collection query language,简称cql

设计思路

  1. 选用mysql的语法作为cql的语法基础
  2. 将cql解析成抽象语法树,也就是将sql进行解析、语法校验、子句拆解,形成按select、from、where、group by、order by子句
  3. 然后将抽象语法树映射到易于集合处理器程序执行的集合处理模板树


    解析过程

抽象语法树 AST结构如下: 大致描述用到的结构,其实际结构比这个要复杂


抽象语法树结构

集合处理器模板树结构如下:


模板树实现

处理器解析过程

解析过程

使用说明

注:cql默认是以mysql的语法为基础来校验的

1   表名必须是字母和数字的组合
    不能是关键字 select、from、group 、by、order、left、join、where
    select中的表名默认支持L(左表)、R(右表)的缩写,所以写关联查询语句的时候,左表名不要起名叫”R”,右表名不要叫“L”
2   字段名必须是字母、数字、-、_ 这几种的组合,不允许含有“.”,小圆点是表名和字段的连接符,比如:table1.pointCode
3   from 子句,只支持单表查询、两表关联查询
    两表关联查询,只支持join、left join两种,都是以左表为基准来查询
    两表的关联查询写法必须是 A join B 或者 A left join B
4   select 子句,不需要明确指定要查询的字段,如果A、B表中存在的字段,在结果T中也存在字段,则会查询出来
    select字段允许重命名,重命名后的字段必须在结果T中的字段中存在
    select字段允许函数,现只支持substr,支持插件式扩展,可以提需求
    select字段不允许分组函数后重命名,分组函数操作后的字段名还是之前的字段,比如sum(value),返回的结果存放在返回集合名为value的属性上
5   group by子句,分组操作的字段是基于关联后的数据集做的操作,so,分组操作的字段不允许带表名
    比如:select SUM(L.value) from A group by A.code,需要改成 select SUM(value) from A group by code
    分组字段也是基于关联后的合并数据集合来做的操作,也不允许出现表名,直接写返回集合所拥有的字段名即可
    如果需要重命名字段,则需要在select 条件中优先重命名字段,再做累加,比如:select R.value as num, sum(num)
    group by不允许出现函数,比如:substr,如果需要做处理,则只需要在select中指定即可
6   order by 的字段是基于关联后的数据集(也就是结果数据集)做的操作,so,排序操作的子弹不允许带表名
7   where 子句,配置关联字段的关系以及过滤条件
    如果是两表关联的关联条件,必须指定字段的表名,比如:L.code=R.code
    非关联条件,只支持正则表达式的匹配方式,sql语句:code like ‘(01|02)’ ,关键字用like指定
            需要注意:正则表达式是java的正则表达式 (山西可能自己改成计费账务的自己写的那版)
            比如:code like ‘^(\\s(01|02))$’,匹配代码:Pattern.compile(”^(\\s(01|02))$”);
            除where子句中的like条件中允许出现“\\”,其他子句不允许出现

执行阶段:
支持三种模式,都是基于pojo的集合设计
每种模式都有两个方法,基于cql的和基于自定义模板的

限定符和类型 方法和说明
static <E> java.util.List<E> execute(java.util.List<E> collections, CollectionProcessTemplate template)
调用该方法,将对集合按设置的模板规则进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
static <T,E> java.util.List<T> execute(java.util.List<E> collections, CollectionProcessTemplate template, java.lang.Class<T> tClazz)
调用该方法,将对集合按设置的模板规则进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
static <E> java.util.List<E> execute(java.util.List<E> collections, java.lang.String cql)
调用该方法,将对集合按cql进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
static <T,E> java.util.List<T> execute(java.util.List<E> collections, java.lang.String cql, java.lang.Class<T> tClass)
调用该方法,将对集合按cql进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
static <T,LE,RE> java.util.List<T> execute(java.util.List<LE> leftCollection, java.util.List<RE> rightCollection, CollectionProcessTemplate template, java.lang.Class<T> tClazz)
调用该方法,将对集合按设置的规则模板进行关联查询处理后,返回设置的T类型的集合 T类型中包括了左集合、左集合的字段 入参两个集合分别代表左集合、右集合,对应SQL关联查询中的左表、右表
static <T,LE,RE> java.util.List<T> execute(java.util.List<LE> leftCollection, java.util.List<RE> rightCollection, java.lang.String cql, java.lang.Class<T> tClazz)
调用该方法,将对集合按cql进行处理后,返回两种类型合并的集合 入参两个集合,支持关联

方法详细资料

public static <E> java.util.List<E> execute(java.util.List<E> collections,
                            java.lang.String cql)
处理方法 调用该方法,将对集合按cql进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
类型参数:
E - 集合中的元素类型
参数:
collections - 要处理的集合
cql - 要处理的规则
返回:
返回处理后的集合
public static <E> java.util.List<E> execute(java.util.List<E> collections,
                            CollectionProcessTemplate template)
处理方法 调用该方法,将对集合按设置的模板规则进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
类型参数:
E - 集合中的元素类型
参数:
collections - 要处理的集合
template - 要处理的规则,需要先new个CollectionProcessTemplate,并进行设置属性
返回:
返回处理后的集合
public static <T,E> java.util.List<T> execute(java.util.List<E> collections,
                              java.lang.String cql,
                              java.lang.Class<T> tClass)
处理方法 调用该方法,将对集合按cql进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
类型参数:
T - 返回的集合元素类型
E - 集合中的元素类型
参数:
collections - 要处理的集合
cql - 要处理的规则
返回:
返回处理后的集合
public static <T,E> java.util.List<T> execute(java.util.List<E> collections,
                              CollectionProcessTemplate template,
                              java.lang.Class<T> tClazz)
处理方法 调用该方法,将对集合按设置的模板规则进行处理后,返回相同类型的集合 入参一个集合,不做关联,只做groupby、orderby、filter
类型参数:
T - 返回的集合元素类型
E - 入口集合中的元素类型
参数:
collections - 要处理的集合
template - 要处理的规则,需要先new个CollectionProcessTemplate,并进行设置属性
返回:
返回处理后的集合,类型为入参指定的集合类型
public static <T,LE,RE> java.util.List<T> execute(java.util.List<LE> leftCollection,
                                  java.util.List<RE> rightCollection,
                                  java.lang.String cql,
                                  java.lang.Class<T> tClazz)
处理方法 调用该方法,将对集合按cql进行处理后,返回两种类型合并的集合 入参两个集合,支持关联
类型参数:
T - 返回的集合元素类型
LE - 入参左集合的元素类型
RE - 入参右集合的元素类型
参数:
leftCollection - 关联集合的左集合
rightCollection - 关联集合的右集合
cql - 要处理的规则
返回:
返回处理的集合,集合的元素包括左集合、右集合的元素
public static <T,LE,RE> java.util.List<T> execute(java.util.List<LE> leftCollection,
                                  java.util.List<RE> rightCollection,
                                  CollectionProcessTemplate template,
                                  java.lang.Class<T> tClazz)
处理方法 调用该方法,将对集合按设置的规则模板进行关联查询处理后,返回设置的T类型的集合 T类型中包括了左集合、左集合的字段 入参两个集合分别代表左集合、右集合,对应SQL关联查询中的左表、右表
类型参数:
T - 返回的集合元素类型
LE - 入参左集合的元素类型
RE - 入参右集合的元素类型
参数:
leftCollection - 关联集合的左集合
rightCollection - 关联集合的右集合
template - 要处理的规则,需要先new个CollectionProcessTemplate,并进行设置属性
返回:
返回处理的集合,集合的元素包括左集合、右集合的元素

测试例子:

@Test
public void testSql(){
    long start = SystemClock.now();
        String cql = "select points addPoint, sum(curPoint), sum(addPoint) from gen left join source where l.pointCode=r.pointCode group by pointCode order by pointCode";
        List<PointMonthDetInfo> pointMonthDetInfos = CollectionProcessor.execute(generalDetInfos, sourceInfos, cql, PointMonthDetInfo.class);
        for (PointMonthDetInfo info : pointMonthDetInfos) {
            System.out.println(JSON.toJSONString(info));
        }

    long end = SystemClock.now();
    System.out.println("cost: " + (end - start));

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容