Anyline

289 阅读7分钟

AnyLine的核心是一个基于spring生态的D-ORM(动态对象关系影射)

ORM

对象关系映射。

与ORM的区别

  • 面向场景不同
    anyline主要面向动态场景,就是运行时随时可变的场景。
    如我们常用的动态数据源,不是在部署时可以固定在配置文件中,
    而是可能在不确定的时间,由不确定的用户提供的不确定数据源。
    表结构等元数据也可能随着着用户或数据源的不同而随时变化。

  • 针对产品不同
    anyline一般不会直接用来开发一个面向终端用户的产品(如ERP、CRM等),
    而是要开发一个中间产品(如低代码平台),让用户通过中间产品来生成一个最终产品。
    再比如用anyline开发一个自定义查询分析工具,让用户通过这个工具根据业务需求生成动态报表。
    anyline不是要提供一个可二次开发的半成品船,而是可以用来造船的动态船坞。

  • 操作对象不同  anyline主要操作元数据,因为在项目开发之初,可能就没有一个如ERP/CRM之类的明确的产品,
    当然也就没有订单、客户之类的具体对象及属性,所以也没什么具体数据可操作。

  • 面向用户(开发设计人员)不同
    anyline要面向的不是开船的人,而是造船的人,而不是使用工具的人,而是设计工具的人。 anyline的大部分代码与灵感也是来自这部分用户的日常实践。

AnyLine解决或提供了什么

动态、运行时

有些数据库不知道具体有哪些字段,所以不能提前建好,故使用这个

Anyline一的切都是面向动态、面向运行时环境 (相对的是可以提前在配置文件中配置,编码之前场景、对象、属性等已预知已确定)
适合于抽象设计阶段(实体概念还不明确或者设计工作不局限于某个特别的实体)
常用于需要大量复杂动态的查询,以及查询的结果集需要经过深度处理的场景

即运行时才能最终确定 动态的数据源、数据结构、展现形式
如我们需要开发一个数据中台或者一个数据清洗插件,编码阶段我们还不知道数据来源、什么类型的数据库甚至不是数据库、会有什么数据结构对应什么样的实体类,
如果需要前端展示的话,更不会知道不同的终端需要什么各种五花八门的数据组合
那只能定义一个高度抽象的实体了,想来想去也只有Collection可以胜任了。

简单快速的操作数据库

最常见的操作:根据条件分页查询一个表的几列
这一动就要倾巢出动一整套的service/dao/vo dto 各种O/mapper,生成个查询条件各种封装、为了拼接个SQL又是各种if else forearch
如果查询条件是由前端的最终用户动态提供的,那Java里if完了还不算完,xml中if也少不了
一旦分了页,又要搞出另一套数据结构,另一组接口,另一组参数(当然这种拙劣的设计只是极个别,不能代表ORM)

简单快速的操作结果集

数据库负责的是存储,其结构肯定是与业务需要不一样的。所以结果集需要处理。当我们需要用Map处理数据或数学计算时,
如最常见的数据格式化、筛选、分组、平均值、合计、方差等聚合计算
再如空值的处理包括, "", null, "null","\n","\r","\t"," "全角、半角等各种乱七八糟的情况
这时就会发现Map太抽象了,除了get/set/forearch好像也没别的可施展了。
要处理的细节太多了,if都不够用了。

动态数据源

再比如多数据源的情况下,要切换个数据源又是IOC又是AOP一堆设计模式全出场。经常是在方法配置个拦截器。
在同一个方法里还能切换个数据源了?
数据中台里有可能有几百几千个数据源,还得配上几千个方法?
数据源是用户动态提交的呢怎么拦截呢?
这不是DB Util的本职工作么,还要借助其他?
哪个项目少了AOP依赖还切换不了数据源了?

重复工作

如果只是写个helloworld,以上都不是问题,没什么解决不了的。但实际工作中是需要考虑工作量和开发速度的。
比如一个订单可能有几十上百列的数据,每个分析师需要根据不同的列查询。有那么几十列上同时需要<>=!=IN FIND_IN_SET多种查询方式算正常吧
不能让开发人员挨个写一遍吧,写一遍是没问题,但修改起来可就不是一遍两遍的事了
所以需要提供一个字典让用户自己去配置,低代码开发平台、自定义报表、动态查询条件应该经常有这个需求。
当用户提交上来一个列名、一个运算算、一组值,怎么执行SQL呢,不能在代码中各种判断吧,如果=怎么合成SQL,如果IN怎么合成SQL

如何实现

数据操作的两个阶段,1.针对数据库中数据 2.针对数据库查询的结果集(内存中的数据)

  1. 提供一个通用的AnylineService实现对数据库的一切操作

  2. 提供一对DataSet/DataRow实现对内存数据的一切数学计算
    DataSet/DataRow不是对List/Map的简单封装 他将是提高我们开发速度的重要工具,各种想到想不到的数学计算,只要不是与业务相关的都应该能实现

使用场景

适用场景

数据结构

DataRow
DataSet
Entity
EntitySet

使用方法:

配置pom依赖,直接注入service,然后使用就行

DataSet set = service.querys("CRM_USER");

Anylineservice 注入AnylineService,使用。里面包含insert,delete,update,query等等

常用的:

查询

1.1简单查询

首先就是就简单的查询一张表的数据

 DataSet game = anylineService.querys("game");

里面的game就是对应的你需要查询的数据库表的名字。

1.2条件查询

有时需要带条件的查询就需要构造一个configStore

ConfigStore configStore = anylineService.condition();
configStore.and(Compare.LIKE,"gname",name).and(Compare.GREAT_EQUAL,"gprice",88).and(Compare.IN,"gid",gids).and(Compare.NOT_IN,"gid",14);
        configStore.or(Compare.EQUAL,"gname","Contractors");
        DataSet game = anylineService.querys("game",configStore);
        game.getRows().stream().forEach(System.out::println);

这个configStore就是我们构造的查询条件,里面可以是equal就是等于,like就是模糊匹配

1.3多表联查

有时需要对多表得查询就要构造RunPrepare

RunPrepare build = TableBuilder.init("orders").inner("game", "game.gid=orders.gid").build();
        DataSet game = anylineService.querys(build, configStore);

2.插入

2.1单条数据插入

 ```java
 //这里ni创建得对象的成员属性名和表的对应字段要能匹配
    Game game = new Game();
    game.setGid(21);
    game.setGname("元素1");
    game.setGprice(67);
    long game1 = anylineService.insert("game", game);
    System.out.println(game1);
 ```

2.2数据批量插入

       List<Game> games=new ArrayList<>();
       for (int i = 0; i < 20; i++) {
           Game game2 = new Game();
           game2.setGid(22+i);
           game2.setGname("元素"+21+i);
           game2.setGprice(67+i);
           games.add(game2);
       }
       anylineService.insert("game",games);

3.删除

3.1条数据删除

    ConfigStore configStore = anylineService.condition();
    configStore.and(Compare.EQUAL,"gid",21);
    long game = anylineService.delete("game", configStore);
    System.out.println(game);

4.修改

4.1单条数据修改

        Game game = new Game();
        game.setGid(21);
        game.setGname("元素喀什");
        game.setGprice(67);
        ConfigStore configStore = anylineService.condition();
        configStore.and(Compare.EQUAL,"gid",21);
        anylineService.update("game",game,configStore);

4.2批量修改

这里需要用到dataset对象进行删除

DataSet game = anylineService.querys("game");
        List<DataRow> rows = game.getRows();
        //这里之所以设置了两个值就是为了好看修改成功没有
        rows.get(0).set("GNAME","基督教撒");
        rows.get(0).set("GPRICE",9);
        //这里需要告诉我们的主键是什么,他修改的时候就会以我们设置的列作为查询条件
        String primaryKeyName = commonService.getPrimaryKey("game");
        for (DataRow row : rows) {
            row.setPrimaryKey(primaryKeyName);
        }
        System.out.println(game.getRows());
        anylineService.update("game",game);

里面有个根据表名获取主键的名方法我就不提供了,我提供sql语句,自己封装在方法里面就可以了,这个实在mapper层做的

@Select("select column_name from information_schema.COLUMNS where TABLE_SCHEMA = (select database()) and TABLE_NAME= #{tableName} and column_key='PRI';")
    String getPrimaryKey(@Param("tableName") String tableName);