# anyline
**Repository Path**: LevelCoder/anyline
## Basic Information
- **Project Name**: anyline
- **Description**: 一个天然的低代码、动态表单、动态数据源底层工具,运行时动态注册切换数据源,自动生成SQL(DDL/DML/DQL),读写元数据,对比数据库结构差异。No-Entity,适配100+关系/非关系数据库。
常用于动态场景的底层支持,如:数据中台、低代码、可视化、工作流、自定义表单、异构数据库迁移同步、物联网车联网数据处理、数据清洗、运行时自定义报表/查询条件/数据结构、爬虫数据解析等
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: http://doc.anyline.org/
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 844
- **Created**: 2024-11-19
- **Last Updated**: 2024-11-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
[](README.md)
[](README_zh_CN.md)
|
|
|
QQ群(86020680) |
微信群 |
过期或满员联系管理员
|
有问题请联系以上群(无论BUG、疑问、需求、源码、竞品) |
***快速测试请参考[【anyline-simple-clear】](https://gitee.com/anyline/anyline-simple-clear)***
***详细语法请参考[【anyline-simple】](https://gitee.com/anyline/anyline-simple)***
关于多数据源,请先阅读
[【六种方式注册数据源】](http://doc.anyline.org/aa/a9_3451)
[【三种方式切换数据源】](http://doc.anyline.org/aa/64_3449)
[【多数据源事务控制】](http://doc.anyline.org/ss/23_1189)
低代码平台、数据中台等场景需要生成SQL/操作元数据参考
[【JDBCAdapter】](http://doc.anyline.org/ss/01_1193)
[【返回SQL方言、导出SQL】](http://doc.anyline.org/aa/70_3793)
[【表结构差异对比及生成DDL】](http://doc.anyline.org/aa/a2_3936)
[【ConfigStore与JSON互换】](http://doc.anyline.org/aa/73_13975)
[【service.metadata】](http://doc.anyline.org/ss/22_1174)
[【SQL.metadata】](http://doc.anyline.org/aa/c1_3847)
## 简介
AnyLine的核心是一个面向运行时的 元数据动态关系映射 主要用于
- 动态注册切换数据源
- 读写元数据
- 对比数据库结构差异
- 生成动态SQL,组合动态查询条件
- 复杂的结果集操作
一个天然的低代码、动态表单、动态数据源底层工具
适配各种关系型与非关系型数据库(及各种国产小众数据库)
常用于动态结构场景的底层支持,作为SQL解析引擎或适配器出现
如:数据中台、可视化、低代码、SAAS、自定义表单、异构数据库迁移同步、 物联网车联网数据处理、
条件/数据结构、 爬虫数据解析等。
参考【[适用场景](http://doc.anyline.org/ss/ed_14)】
##### 数据源注册及切换
注意这里的数据源并不是主从关系,而是多个完全不相关的数据源。
```java
DataSource ds_sso = new DruidDataSource();
ds_sso.setUrl("jdbc:mysql://localhost:3306/sso");
ds_sso.setDriverClassName("com.mysql.cj.jdbc.Driver");
...
DataSourceHolder.reg("ds_sso", ds_sso);
或
DataSourceHolder.reg("ds_sso", pool, driver, url, user, password);
DataSourceHolder.reg("ds_sso", Map params); //对应连接池的属性k-v
//查询ds_sso数据源的SSO_USER表
DataSet set = ServiceProxy.service("ds_sso").querys("SSO_USER");
```
来自静态配置文件数据源(如果是spring环境可以按spring格式)
```properties
#默认数据源
anyline.datasource.type=com.zaxxer.hikari.HikariDataSource
anyline.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
anyline.datasource.url=jdbc:mysql://localhost:33306/simple
anyline.datasource.user-name=root
...更多参数
#其他数据源
anyline.datasource-list=crm,erp,sso,mg
anyline.datasource.crm.driver-class-name=com.mysql.cj.jdbc.Driver
anyline.datasource.crm.url=jdbc:mysql://localhost:33306/simple_crm
anyline.datasource.crm.username=root
anyline.datasource.erp.driver-class-name=com.mysql.cj.jdbc.Driver
anyline.datasource.erp.url=jdbc:mysql://localhost:33306/simple_erp
anyline.datasource.erp.username=root
```
DML
```java
如果是web环境可以
service.querys("SSO_USER",
condition(true, "NAME:%name%", "TYPE:[type]", "[CODES]:code"));
//true表示需要分页,没有传参籹值的条件默认忽略
//生成SQL:
SELECT *
FROM SSO_USER
WHERE 1=1
AND NAME LIKE '%?%'
AND TYPE IN(?,?,?)
AND FIND_IN_SET(?, CODES)
LIMIT 5,10 //根据具体数据库类型
//用户自定义查询条件,低代码等场景一般需要更复杂的查询条件
ConfigStore configs;
service.query("SSO_USER", configs);
ConfigStore提供了所有的SQL操作
//多表、批量提交、自定义SQL以及解析XML定义的SQL参数示例代码和说明
```
读写元数据
```java
@Autowired("anyline.service")
AnylineService service;
//查询默认数据源的SSO_USER表结构
Table table = serivce.metadata().table("SSO_USER");
LinkedHashMap columns = table.getColumns(); //表中的列
LinkedHashMap constraints = table.getConstraints(); //表中上约束
List ddls = table.getDdls(); //表的创建SQL
//删除表 重新创建
service.ddl().drop(table);
table = new Table("SSO_USER");
//这里的数据类型随便写,不用管是int8还是bigint,执行时会转换成正确的类型
table.addColumn("ID", "BIGINT").autoIncrement(true).setPrimary(true).setComment("主键");
table.addColumn("CODE", "VARCHAR(20)").setComment("编号");
table.addColumn("NAME", "VARCHAR(20)").setComment("姓名");
table.addColumn("AGE", "INT").setComment("年龄");
service.ddl().create(table);
或者service.ddl().save(table); 执行时会区分出来哪些是列需要add哪些列需要alter
```
事务
```java
//因为方法可以有随时切换多次数据源,所以注解已经捕捉不到当前数据源了
//更多事务参数通过TransactionDefine参数
TransactionState state = TransactionProxy.start("ds_sso");
//操作数据
TransactionProxy.commit(state);
TransactionProxy.rollback(state);
```
### 已经有ORM了 为什么还要有AnyLine, 与ORM有什么区别
- ***面向场景不同***
anyline主要面向动态场景,就是运行时随时可变的场景。
如我们常用的动态数据源,不是在部署时可以固定在配置文件中,
而是可能在不确定的时间,由不确定的用户提供的不确定数据源。
表结构等元数据也可能随着着用户或数据源的不同而随时变化。
- ***针对产品不同***
anyline一般不会直接用来开发一个面向终端用户的产品(如ERP、CRM等),
而是要开发一个中间产品(如低代码平台),让用户通过中间产品来生成一个最终产品。
再比如用anyline开发一个自定义查询分析工具,让用户通过这个工具根据业务需求生成动态报表。
anyline不是要提供一个可二次开发的半成品船,而是可以用来造船的动态船坞。
- ***操作对象不同***
anyline主要操作元数据,因为在项目开发之初,可能就没有一个如ERP/CRM之类的明确的产品,
当然也就没有订单、客户之类的具体对象及属性,所以也没什么具体数据可操作。
- ***面向用户(开发设计人员)不同***
anyline要面向的不是开船的人,而是造船的人,而不是使用工具的人,而是设计工具的人。
anyline的大部分代码与灵感也是来自这部分用户的日常实践。
- ***所以对用户(开发设计人员)要求不同***
一个ORM用户用了许多年的连接池,他可以只知道配置哪几个默认参数,也能正常开展工作。
但anyline的用户不行,他要求这个团队中至少有一个人要明白其所以然。
### 实际操作中与ORM最明显的区别是
- ***摒弃了各种繁琐呆板的实体类以及相关的配置文件***
让数据库操作更简单,不要一动就是一整套的service/dao/mapping/VOPODTO有用没用的各种O,生成个简单的SQL也各种判断遍历。
- ***强强化了结果集的对象概念***
面向对象的对象不是只有get/set/注解这么弱
需要把数据及对数据的操作封装在一起,作为一个相互依存的整体,并实现高度的抽象
要关注元数据,不要关注姓名、年龄等具体属性
强化针对结果集的数据二次处理能力
如结果集的聚合、过滤、行列转换、格式化及各种数学计算尽量作到一键...一键...
而不要像ORM提供的entity, map, list除了提供个get/set/foreach,稍微有点用的又要麻烦程序员各种判断各种遍历
参考【[疑问与优劣对比](http://doc.anyline.org/ss/ae_1196)】
### 与如何实现
数据操作的两个阶段,1.针对数据库中数据 2.针对数据库查询的结果集(内存中的数据)
- ***提供一个通用的AnylineService实现对数据库的一切操作***
- ***提供一对DataSet/DataRow实现对内存数据的一切数学计算***
DataSet/DataRow不是对List/Map的简单封装 他将是提高我们开发速度的重要工具,各种想到想不到的数学计算,只要不是与业务相关的都应该能实现
## AnyLine解决或提供了什么
### 动态、运行时
即运行时才能最终确定 动态的数据源、数据结构、展现形式
如我们需要开发一个数据中台或者一个数据清洗插件,编码阶段我们还不知道数据来源、什么类型的数据库甚至不是数据库、会有什么数据结构对应什么样的实体类,
如果需要前端展示的话,更不会知道不同的终端需要什么各种五花八门的数据组合
那只能定义一个高度抽象的实体了,想来想去也只有Collection