跳转到内容

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 ccreatedAt
from
base_User u,
base_Company c
where
u.`name` = c.`name`
limit
2;

但是可以换成Join写法来实现完全相同的功能

select
u.id as uid,
u.name as uname,
c.id as cid,
c.createdAt as ccreatedAt
from
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_code
FROM
customize_tenant;

1.2.3 不支持having语法

SELECT
customerId,
SUM(activeSrCount + activeRcCount + activePcCount) activeCount
FROM
test_Model
WHERE
yearMonth >= xxx
GROUP BY
customerId
HAVING
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 ccreatedAt
from
base_User u
left join base_Company c on u.`name` = c.`name`
limit
2;

限制项:

  1. 必须指定表别名以及字段别名:举例select id,name from base_User u left join base_Company on xxx,原因是无法知道select的字段属于哪个模型
  2. 不允许select *:举例select * from base_User u left join base_Company on xxx,请显示声明需要查询的字段
  3. 如果显式使用Join语法,则不可以同时使用关联模型查询

1.3.3 AS

TSQL支持设置表别名以及字段别名,与标准SQL的区别点在于需要显式声明AS关键字

select a.`id` from base_User as a;
select `id` as aid from base_User

2. How TSQL work

了解TSQL的特性和限制之后,本章将简要讲述TSQL是怎么工作的。

2.1 TSQL时序图

TSQL时序图

2.2 TSQL处理流程(DataStore)

TSQL处理流程

3. TSQL vs GQL

部分同学使用过Trantor旧版本,旧版本中需要使用GraphQL语法访问DataStore,从013版本开始我们提供了TSQL,并从016版本开始完全使用TSQL访问DataStore,本章重点讲述GQL和TSQL的差异点,如果没有使用过旧版本trantor不需要关注本章。

3.1 功能差异

GQL APITSQL API
仅创建主模型支持支持
同时创建主模型和关联模型支持不支持
仅修改主模型支持支持
同时修改主模型和关联模型支持不支持
仅删除主模型支持支持
同时删除主模型和关联模型不支持不支持
仅查询主模型支持支持
同时查询主模型和多级关联模型支持支持

TSQL API对于单模型CRUD支持较好,基本上各种SQL都支持,但是相对于GQL API来说,对关联模型的支持较弱:

  1. 不支持在创建或修改主模型时,同时创建或修改关联模型

举例:

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创建和更新只能更新一个模型的数据

  1. 不支持查询关联模型时,对关联模型分页

举例:

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;