执行流程-DML/DDL/metadata
这三部分的执行流程,基本上已固定,顶级父类统一实现。主要区别DDL命令合成、metadata命令合成、metadata结果集封装三个子流程。其中metadata的差异最大。
比较乐观的是大部分数据库可以归类到pg,mysql,oracle等几个系列,所在大部分方法在父类中已经实现了,只有极个别不兼容的需要在子类中覆盖只有。
还有几个小差异如于数据类型、分页,内置函数工作量都有限
- DML
- DDL
- metadata
- 全部展开
DML的主要区别在分页方式及增量插入
看一个常用的查询DML:service.querys(String src, ConfigStore configs, String ... conditions);
service获取方式参考【AnylineService】最好先了解一下数据库操作相关的【设计概要】
一、querys方法 会先检测src类型,可选类型:- 表名,多数据源时表名上可以带数据源前缀如<ds1>crm_user,参考【数据源注册和切换】
- 原生SQL,SQL中可以带占位符
- xml定义的SQL的id
- RunPrepare 在地代码平台、自定义报表等多表关联时会用到,参考【多表关联】
service中的createRunPrepare(String src)方法会解析src中的表名、列名、占位符并最终生成RunPrepare,参考【Param/ConfigStore/RunPrepare/Run】和【CreateRunPrepare】
这里的conditions可以是原生的SQL查询条件也可以是order group having,也可以是K:V格式的条件,如:querys("CRM_USER", "order by id","group by TYPE_CODE", "AGE:20", "SEX=1") 没有先后顺序
最后把RunPrepare与ConfigStore提交给dao.querys
二、dao中DataRuntime根据当前查询的数据源或连接信息 检测数据库类型,同时也确定了adapter实例,最后把参数提交给adapter.querys(),参考【DriverAdapter定位过程】
service、dao、jdbc、数据源、连接池、事务管理器是一组一一对应的实例,由DataRuntime统一维护几者之间的关系,参考【数据源注册过程】
注意早期版本中这里会涉及到数据源切换,新版本中不再有切换数据源的概念,每个service,dao都对应着固定的数据源,参考【为什么取消了ThreadLocal切换数据源的方式】
三、到了adapter这一步已经区分开数据库
-
生成SQL
不同的数据库生成的SQL语法不同,每个数据库会对应各自的adapter,是anyline要实现重点。
DML部分因为大致相同基本已经按ISO/IEC 9075标准完成,(基本是按2016版本,不要太旧也不要太新)
-
调用驱动接口查询数据库,
这一步因为是JDBC定义的统一接口,所以一般由各个adapter的父类统一实现。稍有区别的是注意有些内存数据库不支持返回自增序列值
非JDBC的数据库由各自驱动实现(这一部分还刚刚开始)
-
封装结果集
结果集常用DataSet/DataRow或EntitySet/Entity
如果要求速度会用List/Map或者采用流式查询
DDL的差异也不是很大,主要是数据类型、自增、alter有所不同。
看一个常用的创建表的操作
Table table = new Table("sso_user")
table.addColumn("ID", "bigint").primary(true).autoIncrement(true).setComment("主键");
service.ddl().create(table);
一、service中几乎不作什么操作,只是解析一下数据库源,格式化一下参数,如果是save判断一下是create还是alter,最后次给dao.crate(Table)
二、dao里了不作实际操作,只是解析一下数据库类型定位adapter,实际操作最终交给了adapter.create(Table)
三、这里是重点,adapter中DDL相关的方法分成了三组
-
调用入口
boolean create(DataRuntime runtime, Table meta)
入口方法负责整个流程的维护。一般由父类DriverAdapter完成,极各别的数据库执行流程不同可以在具体的adapter中覆盖父类入口方法 -
命令合成
List<Run> buildCreateRun(DataRuntime runtime, Table meta)
这里的一个命令可能需要多个访求共同合成,如
StringBuilder charset(DataRuntime runtime, StringBuilder builder, Table meta) 表编码相关
StringBuilder comment(DataRuntime runtime, StringBuilder builder, Table meta) 表注释相关
有些数据库不支持在创建表时添加注释的可能需要单独添加注释的命令
List<Run> buildAppendCommentRun(DataRuntime runtime, Table meta)
还会涉及到添加索引等子命令
List<Run> buildAddRun(DataRuntime runtime, Index meta)
这里需要由每个数据库的adapter具体实现,但是因为数据库就这么几类,大部分都是基于pg,mysql,oracle,
所以我们在anyline-data-jdbc提供了几个基础类如OracleGenusAdapter,
oracel以及oracle系列的adapter一般继承自OracleGenusAdapter,这个类中实现了大部分oracle系列的语法,有极少数语法不兼容的情况可以在具体的adapter中覆盖父类方法 -
命令执行
这一步基本上没什么差异,也是由顶级父类统一调用
这一部分是各数据库之间差异最大的一部分。
看一个常用的查询表结构的方法
Table table = service.metadata().table("sso_user");
前两步与DDL类似
一、service中几乎不作什么操作,只是控制几个简单的流程,补充几个默认参数后交给dao
二、dao里了不作实际操作,只是解析一下数据库类型定位adapter,实际操作最终交给了adapter.table(String)
三、这里是重点,adapter中metadata相关的方法分成了三组
-
调用入口
<T extends Table> List<T> tables(DataRuntime runtime, String random, boolean greedy, Catalog catalog, Schema schema, String pattern, String types, boolean strut)
入口方法负责整个流程的维护。一般由父类DriverAdapter完成,极各别的数据库执行流程不同可以在具体的adapter中覆盖父类入口方法
-
命令合成
List<Run> buildQueryTableRun(DataRuntime runtime, boolean greedy, Catalog catalog, Schema schema, String pattern, String types)
这里也是需要每个数据库的adapter具体实现,主要主是确定哪部分元数据存在哪个表中,在anyline-data-jdbc同样提供了几个基础类如OracleGenusAdapter,
有极少数语法不兼容的情况可以在具体的adapter中覆盖父类方法,这也是工作量最大的一部分了
-
结果集封装
<T extends Table> List<T> tables(DataRuntime runtime, int index, boolean create, Catalog catalog, Schema schema, List<T> tables, DataSet set)
就是解析上一步查询的结果集DataRow,把属性值赋给Table,Column等几个类