TSQL概述
DS作为业务模块的数据访问代理层(调用路径为:业务模块 —> DS —> DB),在提供GQL API访问数据库的基础上,增加了TrantorSQL(简称TSQL) API访问数据库的能力。
1. TSQL定义
TSQL全称为Trantor-TSQL,是一种特殊的SQL语法,语法层面在MySQL语法基础上增加了一些特性,删除了一些语法。
核心的差异为TSQL是面向模型的,SQL语法是面向表结构的
TSQL中的表名为模型Key,字段名为模型字段名,比如:select name from test_TestCompany where id > 1000,其中test_TestCompany是模型Key,id和name是模型字段名
编写TSQL时候需要记住要面向模型而不是面向表结构编程,这一点设计是基于一个背景,即在trantro研发体系中所有操作都是面向模型的,模型定义是稳定的,而表结构是相对不稳定的,项目运行在不同的数据库下产生的表名和字段名是有差异的,因此我们需要面向一个稳定的元信息去构造TSQL,这样业务逻辑才不会跟底层的存储中间件绑定。
1.1 增加的特性
1.1.1 关联模型操作
TSQL可通过点号(.)引用关联模型字段名,比如:select items.name from test_TestOrder where items.amount = 1,其中items是test_TestOrder的直接关联模型
这种关联模型操作会包含两部分,一个是关联模型查询,一个是关联模型where条件
select `id`, `code`, `items`.`name` from `test_TestOrder` where `items`.`amount` = 1这个例子中就展示了通过items这个关联模型的字段条件进行过滤,查询Order表的数据以及关联的item表数据
1.1.2 新增函数
针对多值字典类型,我们提供了新的函数来表达交集、包含这种语义(暂未提供)
1.2 不支持语法
TSQL相比MySQL语法存在一些不支持项,在编写TSQL时候需要注意
1.2.1 不支持select from多个模型
select u.id as uid, u.name as uname, c.id as cid, c.createdAt as ccreatedAtfrom base_User u, base_Company cwhere u.`name` = c.`name`limit 2;但是可以换成Join写法来实现完全相同的功能
select u.id as uid, u.name as uname, c.id as cid, c.createdAt as ccreatedAtfrom base_User u left join base_Company c on u.`name` = c.`name`limit 2;1.2.2 不支持CASE WHEN/ WHEN THEN这种逻辑判断分支语法
SELECT CASE mall_id WHEN '50600501' THEN '50606' ELSE LEFT (mall_id, 5) END AS org_id, store_codeFROM customize_tenant;1.2.3 不支持having语法
SELECT customerId, SUM(activeSrCount + activeRcCount + activePcCount) activeCountFROM test_ModelWHERE yearMonth >= xxxGROUP BY customerIdHAVING activeCount >= 2 and pvCount >= 2;1.3 注意事项
1.3.1 字段名/表名/预编译占位符
构造TSQL时,如果手写TSQL,然后使用传入字符串的API,需要注意字段名和表名最好都加上反引号,避免与MySQL关键字冲突导致解析异常
举例,假设模型中存在字段key、version、max,本次需要查询这三个字段值
异常TSQL
select key,version,max from base_User where key = "test";合法TSQL
select `key`,`version`,`max` from base_User where `key` = "test";假如搜索条件需要使用预编译模式查询(Select类的SQL可以使用预编译提升性能,Insert、Update、Delete即使使用预编译跟非预编译SQL也不会有区别),需要注意预编译占位符需要使用英文的问号而不是中文的问号
异常TSQL
select `key`,`version`,`max` from base_User where `key` = ?;合法TSQL
select `key`,`version`,`max` from base_User where `key` = ?;如果使用TSQL DSL构造TSQL则不需要关注字段名、表名、预编译占位符这种细节,DSL会自动给字段名和表名添加反引号
1.3.2 Join语法
TSQL支持Join语法,支持inner join、cross join、left join、right join、straight join
select u.id as uid, u.name as uname, c.id as cid, c.createdAt as ccreatedAtfrom base_User u left join base_Company c on u.`name` = c.`name`limit 2;限制项:
- 必须指定表别名以及字段别名:举例select
id,namefrom base_User u left join base_Company on xxx,原因是无法知道select的字段属于哪个模型 - 不允许select *:举例select * from base_User u left join base_Company on xxx,请显示声明需要查询的字段
- 如果显式使用Join语法,则不可以同时使用关联模型查询
1.3.3 AS
TSQL支持设置表别名以及字段别名,与标准SQL的区别点在于需要显式声明AS关键字
select a.`id` from base_User as a;select `id` as aid from base_User2. How TSQL work
了解TSQL的特性和限制之后,本章将简要讲述TSQL是怎么工作的。
2.1 TSQL时序图

2.2 TSQL处理流程(DataStore)

3. TSQL vs GQL
部分同学使用过Trantor旧版本,旧版本中需要使用GraphQL语法访问DataStore,从013版本开始我们提供了TSQL,并从016版本开始完全使用TSQL访问DataStore,本章重点讲述GQL和TSQL的差异点,如果没有使用过旧版本trantor不需要关注本章。
3.1 功能差异
| GQL API | TSQL API | |
|---|---|---|
| 仅创建主模型 | 支持 | 支持 |
| 同时创建主模型和关联模型 | 支持 | 不支持 |
| 仅修改主模型 | 支持 | 支持 |
| 同时修改主模型和关联模型 | 支持 | 不支持 |
| 仅删除主模型 | 支持 | 支持 |
| 同时删除主模型和关联模型 | 不支持 | 不支持 |
| 仅查询主模型 | 支持 | 支持 |
| 同时查询主模型和多级关联模型 | 支持 | 支持 |
TSQL API对于单模型CRUD支持较好,基本上各种SQL都支持,但是相对于GQL API来说,对关联模型的支持较弱:
- 不支持在创建或修改主模型时,同时创建或修改关联模型
举例:
GQL可以级联创建或者更新,只需要在传入父模型对象时带有子模型对象即可
mutation { createManytest_center_Model3( data: [ { stringField: "2李四2" intField: 12 oneToOneField: { create: { booleanField: true stringField: "1string1" partitionKeyField: "1" } } oneToManyField: { create:[ { dateTimeField: "2020-04-28 11:11:11" partitionKeyField: "1" } ] } manyToManyField: { create:[ { stringField: "1string1" partitionKeyField: "1" } ] } } ] ) { _COUNT }}TSQL创建和更新只能更新一个模型的数据
- 不支持查询关联模型时,对关联模型分页
举例:
gql中可以在返回字段上通过skip和first指定子模型分页
query { partner_center_Partners( where: { id: 1 } orderBy: updatedAt_DESC skip: 0 first: 10 ) { id name labels(skip: 10, first: 20) { id name } }}但是TSQL无法表达这种语义,这时候labels字段查询的就是关联的全部数据
select `id`, `name`, `labels`.`id`, `labels`.`name`from `partner_center__partner`limit 0, 10;