[微服务] 阿里云分布式事务GTS聚合文章
文章参考来源:
微服务架构下的事务一致性: https://www.jianshu.com/p/7ebe567c7135
深入解读微服务架构下分布式事务解决方案: https://www.jianshu.com/p/f04cc1a696b4
GTS官方:https://help.aliyun.com/document_detail/48726.html
GTS解密--GTS的原理、架构与特点: https://yq.aliyun.com/articles/334238
GTS for DRDS分布式事务的实现理解: https://yq.aliyun.com/articles/213637
是的,这是一篇搬运文章。如果侵权请与我联系删除,所有内容归原作者所有。
一、关于GTS的介绍
GTS技术栈
GTS采用基于XA架构优化的技术路线,在保留XA架构灵活性的优点下,通过将XA提交中的第一阶段与第二阶段解耦,将提交过程转换为第一阶段本地事务提交+第二阶段异步清理的方式,从而提供提升系统性能,同时通过在GTS内部维护应用级别的日志与锁信息,实现了全局事务的回滚与并发控制。
GTS方案认为XA性能低效的根本原因是采用了阻塞协议。在分布式事务提交的第一阶段等待最慢的一个事务分支完成,即使在不存在锁冲突的情况下,各事务分支的数据库连接依然会被挂起所占用的资源都不能够释放,以防止全局事务提交前释放资源所造成的数据不一致。对于业务流量极高的大规模互联网企业,难以接受 XA 两阶段提交协议所带来的巨大性能开销。
GTS架构包含的组件与XA完全相同,示意架构如下图。
GTS全局事务处理流程与XA一致,也包括全局事务注册、数据访问与全局事务提交三个步骤,但在第二步与第三步的内部处理上与XA不同:
- 第二步数据访问中,各事务分支完成数据操作的同时,会将全局事务信息(锁与日志信息)存储在当前数据库的表中。
- 第三步全局事务提交中,采用一阶段本地事务提交+二阶段异步清理的方式。首先对各数据库做本地事务的提交,并释放数据库连接等系统资源,然后,向TM发出全局事务提交请求,TM收到请求后,立即返回成功,TM后续实际工作是对各个数据库使用全局事务标识符进行全局事务信息的清理。
GTS与XA在全局事务的故障恢复处理与并发控制采用了不同的实现机制:
- XA两阶段协议是基于数据库内核的日志与锁信息实现全局事务的回滚与并发控制。由于GTS一阶段本地事务提交中,会直接提交本地事务并释放连接,此时数据库内核的日志与锁表对全局事务不再有效。在第二步中,GTS会将日志和锁信息存储在表中,当事务本地提交后,日志和锁信息被持久化保存,用于实现全局事务的并发控制与故障恢复。
- GTS的故障恢复只有UNDO操作没有REDO操作,日志表中存储了UNDO需要的信息,包括行记录标识、全局事务号、镜像查询语句、操作的前像与操作的后像。当发生故障时,对于已经本地提交的数据库,从UNDO表中找到修改的记录,记录的操作前像和操作后像,使用镜像查询语句从数据库中读取该记录的当前值。如果当前值与记录操作后像相同,则直接使用操作前像进行恢复,否则报警,进行人工处理。
- GTS的全局锁表中存储了记录的加锁信息。封锁的粒度是行(记录),锁的类型包括共享锁和互斥锁,对于同一个记录,加锁的规则是共享锁与共享锁不冲突,共享锁与互斥锁冲突、互斥锁与互斥锁冲突。对插入(INSERT)、修改(UPDATE)、删除(DELETE)、更新模式的锁定查询(SELECT… FOR UPDATE) 操作加互斥锁。对于共享模式的锁定查询 (SELECT…LOCK IN SHARE MODE) 操作加共享锁。若没有锁冲突,在GTS锁表中,增加一行记录,表示加锁成功。
- GTS的默认隔离级别为读未提交(脏数据),使用SELECT… FOR UPDATE和SELECT…LOCK IN SHARE MODE,可使查询隔离级别提升至读已提交。
GTS的架构与处理流程
架构
下图描述了GTS一种可能的实现架构。
与XA架构相同,GTS架构由应用、事务管理器、资源管理器三个部分组成。资源管理器由事务分支处理模块、镜像查询构造模块、并发控制模块、恢复控制模块,以及存储在数据库中的GTS事务信息(GTS锁表与GTS日志表)等组成。
- 事务分支处理模块:是资源管理器的外部接口,并完成内部各模块的调用。
- 镜像查询构造模块:从Insert、Update、Delete语句,生成该操作对应记录集的镜像查询语句。例如table_name表包含两个字段column1和column2,column1为主键,则镜像查询语句为select column1, column2 from table_name where column1=v1。
- 并发控制模块:基于GTS事务锁表,维护读写并发控制。锁表定义如下:
字段名 | 字段类型 | 字段描述 |
---|---|---|
ID | 整数 | 自增主键 |
TABLE_NAME | 字符串 | 表名 |
KEY_VALUE | 整数 | 数据行ID |
XID | 字符串 | 全局事务标识 |
XLOCK | 整数 | 互斥锁标记 |
SLOCK | 整数 | 共享锁标记 |
BRANCH_ID | 整数 | 事务分支标识 |
- 恢复控制模块:基于GTS日志表,进行故障恢复。 日志表定义如下:
字段名 | 字段类型 | 字段描述 |
---|---|---|
ID | 整数 | 自增主键 |
GMT_CREATE | 时间 | 创建时间 |
GMT_MODIFIED | datetime | 修改时间 |
XID | 整数 | 全局事务ID |
BRANCH_ID | 整数 | 分支事务ID |
ROLLBACK_INFO | longblob | 查询语句、前像与后像 |
STATUS | 整数 | 状态 |
SERVER | 字符串 | 分支所在DB IP |
主要流程序列图
分别描述了insert/delete/update操作、读已提交操作、提交操作和回滚操作等四个操作的序列图(一种可能的实现方式)。
insert/delete/update操作流程序列图
读已提交操作流程序列图
提交操作流程序列图
回滚操作流程序列图
GTS的优势与约束
与基于消息队列与TCC补偿模式的分布式事务相比,在性能满足的情况下,GTS更好的应用灵活性与数据一致性:
- 灵活性:数据库应用基本实现零修改,同时,基于XA模型,可方便的支持消息队列数据库等多种RM。
- 数据一致性:GTS 的缺省事务隔离级别为读未提交,该模式下可以达到分布式事务的最大性能,但可能会读到脏数据。对于一致性要求高的应用,在性能允许的情况下,可以采用已提交读语句(for update、lock in share mode)将隔离级别提升至读已提交。
根据GTS实现机制的特点,其应用场景上有以下约束:加锁操作记录数量不能太大,操作冲突不能太多,加锁时间不能太长。违法以上约束时,GTS内部会占用过多资源、锁冲突和回滚增加,导致性能的下降。电商、物流、金融、零售行业中的核心交易场景有着高并发,高性能,单次操作数据集小,事务响应时间敏感的特点,GTS类方案在此类场景中有着广泛和良好的应用前景。
二、GTS for DRDS分布式事务的实现理解
GTS解决使用 DRDS 进行分库分表后产生的跨分库事务问题
DRDS 通过分库分表实现数据水平拆分, 来解决单机关系型数据库扩展性问题. 但是原有单库单表进行分库分表后, 单表的数据被分散到多个库的表中, 原来对单表多行数据进行的变更, 可能会变为对多库多表的数据变更,即单机本地事务变成了分布式事务。
DRDS 本身不支持分布式事务, 上述场景下再采用原来的单库事务进行操作会导致失败。在 DRDS 中加入 GTS 能够实现这种多个库交易操作的原子性,解决分布式数据库跨库事务的问题
应用端使用分布式事务流程,手工处理事务的典型 SQL 语句步骤如下:
1.set autocommit=false //开启事务
2.select last_txc_xid() //注册一个 GTS 事务
3.insert/update/delete 等业务 SQL
4.commit 或者 rollback //全局提交或回滚
5.autocommit=true //恢复自动提交
通过后端RDS的SQL审计可以查看到在分布式事务情况下分库的处理过程:
插入类型:
序号 |
SQL明细 |
1 |
SET autocommit=0 |
2 |
select * from `USER_TBL` limit 1 |
3 |
SHOW FULL TABLES FROM `marcotest_iirz_0004` LIKE 'user_tbl' |
4 |
SHOW FULL COLUMNS FROM `user_tbl` FROM `marcotest_iirz_0004` LIKE '%' |
5 |
SHOW INDEX FROM `user_tbl` FROM `marcotest_iirz_0004` |
6 |
/* 0aacc85e15058276714612682d3f81/9// *//*DRDS /11.193.54.46/bc105690c801000-d/ */insert into `user_tbl` ( `u_id`, `u_name`, `u_phone`, `u_national`, `createtime`, `updatetime`) values ( 7927652, 'marco7809361834', '8874414727236', 'China-RDS000', '2017-07-09 21:42:50', '2017-07-09 21:42:50') |
7 |
SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL` WHERE user_tbl.U_ID = 7927652 |
8 |
INSERT INTO txc_undo_log(id, xid, branch_id, rollback_info, gmt_create, gmt_modified, status, server) VALUES(769948877,'10.152.29.148:8091:769948876',769948877,'{\"branchId\":769948877,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058276714612682d3f81/9// *//*DRDS /11.193.54.46/bc105690c801000-d/ */insert into `user_tbl` ( `u_id`, `u_name`, `u_phone`, `u_national`, `createtime`, `updatetime`) values ( 7927652, \'marco7809361834\', \'8874414727236\', \'China-RDS000\', \'2017-07-09 21:42:50\', \'2017-07-09 21:42:50\') \",\"sqlType\":\"INSERT\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":31553,\"rTFromLastPoint\":1,\"registBranch\":true,\"server\":\"10.152.29.148:8091\",\"status\":0,\"writeKeys\":\"user_tbl:7927652\",\"xid\":\"10.152.29.148:8091:769948876\"}',now(),now(),0,'10.152.29.148:8091') ON DUPLICATE KEY UPDATE id = 769948877,xid = '10.152.29.148:8091:769948876',branch_id = 769948877,rollback_info = '{\"branchId\":769948877,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058276714612682d3f81/9// *//*DRDS /11.193.54.46/bc105690c801000-d/ */insert into `user_tbl` ( `u_id`, `u_nam |
9 |
commit |
10 |
SET autocommit=1 |
11 |
delete from txc_undo_log where id = 769948877
|
更新类型:
序号 |
SQL明细 |
1 |
SET autocommit=0 |
2 |
select * from USER_TBL limit 1 |
3 |
SHOW FULL TABLES FROM `marcotest_iirz_0004` LIKE 'user_tbl' |
4 |
SHOW FULL COLUMNS FROM `user_tbl` FROM `marcotest_iirz_0004` LIKE '%' |
5 |
SHOW INDEX FROM `user_tbl` FROM `marcotest_iirz_0004` |
6 |
SELECT USER_TBL.U_PHONE,USER_TBL.U_NAME,USER_TBL.U_NATIONAL,USER_TBL.CREATETIME,USER_TBL.U_ID,USER_TBL.UPDATETIME FROM USER_TBL WHERE USER_TBL.`u_id` = 7927652 FOR UPDATE |
7 |
/* 0aacc85e15058261818692667d3f81/9// *//*DRDS /11.193.54.46/bc0ffc01f801000-d/ */update `user_tbl` set `u_national` = 'China-RDS000--' where (`u_id` = 7927652) |
8 |
SELECT USER_TBL.U_PHONE,USER_TBL.U_NAME,USER_TBL.U_NATIONAL,USER_TBL.CREATETIME,USER_TBL.U_ID,USER_TBL.UPDATETIME FROM USER_TBL WHERE U_ID=7927652 |
9 |
INSERT INTO txc_undo_log(id, xid, branch_id, rollback_info, gmt_create, gmt_modified, status, server) VALUES(969949165,'10.152.29.138:8091:969949163',969949165,'{\"branchId\":969949165,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000--\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1505826181000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT USER_TBL.U_PHONE,USER_TBL.U_NAME,USER_TBL.U_NATIONAL,USER_TBL.CREATETIME,USER_TBL.U_ID,USER_TBL.UPDATETIME FROM USER_TBL\",\"sql\":\"/* 0aacc85e15058261818692667d3f81/9// *//*DRDS /11.193.54.46/bc0ffc01f801000-d/ */update `user_tbl` set `u_national` = \'China-RDS000--\' where (`u_id` = 7927652)\",\"sqlType\":\"UPDATE\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":19155,\"rTFromLastPoint\":0,\"registBranch\":true,\"server\":\"10.152.29.138:8091\",\"status\":0,\"writeKeys\":\"user_tbl:7927652\",\"xid\":\"10.152.29.138:8091:969949163\"}',now(),now(),0,'10.152.29.138:8091') ON DUPLICATE KEY UPDATE id = 969949165,xid = '10.152.29.138:8091:969949163',branch_id = 969949165,rollback_info = '{\"branchId\":969949165,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7 |
10 |
commit |
11 |
SET autocommit=1 |
12 |
delete from txc_undo_log where id = 969949165 |
删除类型:
序号 |
SQL明细 |
1 |
SET autocommit=0 |
2 |
select * from `USER_TBL` limit 1 |
3 |
SHOW FULL TABLES FROM `marcotest_iirz_0004` LIKE 'user_tbl' |
4 |
SHOW FULL COLUMNS FROM `user_tbl` FROM `marcotest_iirz_0004` LIKE '%' |
5 |
SHOW INDEX FROM `user_tbl` FROM `marcotest_iirz_0004` |
6 |
SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL` WHERE `USER_TBL`.`u_id` = 7927652 FOR UPDATE |
7 |
/* 0aacc85e15058271185702675d3f81/9// *//*DRDS /11.193.54.46/bc10169d0401000-27/ */delete from `user_tbl` where (`u_id` = 7927652) |
8 |
INSERT INTO txc_undo_log(id, xid, branch_id, rollback_info, gmt_create, gmt_modified, status, server) VALUES(869948781,'10.152.29.56:8091:869948780',869948781,'{\"branchId\":869948781,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000--\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1505826181000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058271185702675d3f81/9// *//*DRDS /11.193.54.46/bc10169d0401000-27/ */delete from `user_tbl` where (`u_id` = 7927652)\",\"sqlType\":\"DELETE\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":40160,\"rTFromLastPoint\":1,\"registBranch\":true,\"server\":\"10.152.29.56:8091\",\"status\":0,\"writeKeys\":\"user_tbl:7927652\",\"xid\":\"10.152.29.56:8091:869948780\"}',now(),now(),0,'10.152.29.56:8091') ON DUPLICATE KEY UPDATE id = 869948781,xid = '10.152.29.56:8091:869948780',branch_id = 869948781,rollback_info = '{\"branchId\":869948781,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000--\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1505826181000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058271185702675d3f81/9// *//*DRDS /11.193.54.46/bc10169d0401000-27/ */delete from `user_tbl` where (`u_id` = 7927652)\",\"sqlType\":\"DELETE\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":40160,\"rTFromLastPoint\":0,\"registBranch\":true,\"server\":\"10.152.29.56:8091\",\"s |
9 |
commit |
10 |
SET autocommit=1 |
11 |
delete from txc_undo_log where id = 869948781 |
客户端发起分布式事务的时候会获取一个全局事务ID,每个分库的任何更新操作前会发起分支事务或者BranchID,任何进行更新操作,当前客户端发起全局提交时,GTS会对每个分库的undo_log表插入回滚信息,然后提交(如果任一分库提交失败,使用回滚信息进行回滚操作);等所有分库提交成功后,在删除所有分库的回滚信息;
回滚信息主要是通过查询表结构元数据及通过主键来查询更新前后的行数据,所有使用GTS分布式事务涉及的表一定要有主键;
可以看看txc_undo_log表结构,在每个分库都会有一张:
XID:XID,即 GTS 分布式事务的全局事务 ID,GTS 服务会为每一个分布式事务生成一个全局唯一的分布式事务 ID
Branch_id:GTS 分布式事务的分支事务 ID,它是事务分支的唯一标识。XID 和 BranchId 是一对多的包含关系,即一个全局事务可能包含多个事务分支
Rollback_info:回滚信息,主要是保存UNDO LOG;
三、尚存不中
很明显,从上面第二点可以看出,其实是在执行增删改之前,先查出对应的数据,存起来以用于回滚。问题就在这里了,就是增删改的SQL不能太复杂,否则,目前GTS很难去判断如何取出对应的数据进行存储的。
阿里云上也有关于这些说明: https://help.aliyun.com/document_detail/48795.html (内容可能会有更新)
GTS 事务目前支持 INSERT、UPDATE、DELETE 三类 DML 语法的部分功能,不支持 SQL 嵌套;不支持多表复杂 SQL;不支持存储过程、触发器;不支持批量 SQL。
SQL 的支持范围还在不断扩大,下面的 SQL 类型都是已经经过 GTS 产品组的严格验证,建议在这个范围内使用,其它 SQL 如果希望使用,请提出工单申请来确认。
DML 语句
类型 | SQL 实例 | 是否支持 |
---|---|---|
INSERT | INSERT INTO tb1_name (col_name,…) VALUES ({expr | FAULT},…),(…),… 或. INSERT INTO tb1_name SET col_name={expr | DEFAULT}, … |
是 |
UPDATE | UPDATE tb1_name SET col_name1=expr1 [, col_name2=expr2 …] [WHERE where_definition] |
是 |
DELETE | DELETE FROM tb1_name [WHERE where_definition] | 是 |
SELECT | SELECT [ALL | DISTINCT | DISTINCTROW ] select_expr, … FROM tb1_name [WHERE where_definition] |
是 |
REPLACE | REPLACE [LOW_PRIORITY | DELAYED] [INTO] tb1_name [(col_name,…)] VALUES ({expr | DEFAULT},…),(…),… 或 REPLACE [LOW_PRIORITY | DELAYED] [INTO] tb1_name SET col_name={expr | DEFAULT}, … |
否 |
TRUNCATE | TRUNCATE [TABLE] tb1_name | 否 |
SQL 修饰
GTS 的隔离级别默认为读未提交,该模式中下表 select 语句的 SQL 修饰用法都是支持的;使用 hint 可以让 GTS 达到读已提交,该模式下 select 语句的用法只能部分支持,具体的支持强度如下表所示。
GTS 的读 hint 为:/+txc({ ‘LEVEL’:’READCOMMITED’})/,用法举例如下:/+txc({ ‘LEVEL’:’READCOMMITED’})/select name from tb where id =1;
DML语句支持
类型 | SQL 实例 | 是否支持 |
---|---|---|
AND & OR | UPDATE … WHERE col_name1=expr1 AND col_name2= expr2 | 是 |
LIKE | UPDATE … WHERE col_name1 LIKE ‘NE’ | 是 |
通配符 | UPDATE … WHERE col_name1 LIKE ‘NE%’ | 是 |
BETWEEN | UPDATE … WHERE col_name1 BETWEEN expr1 AND expr2 | 是 |
ON DUPLICATE | INSERT INTO tb1_name [(col_name,…)] VALUES ({expr | DEFAULT},…),(…),… [ ON DUPLICATE KEY UPDATE col_name=expr, … ] |
是 |
Select 语句支持
类型 | SQL 实例 | 读未提交 | 读已提交 |
---|---|---|---|
AND & OR | SELECT * FROM tb1_name WHERE col_name1=expr1 AND col_name2= expr2 | 是 | 是 |
ORDER BY | SELECT col_name1, col_name2 FROM tb1_name ORDER BY col_name1 | 是 | 是 |
GROUP BY | SELECT col_name1, col_name2 FROM tb1_name GROUP BY col_name1 | 是 | 是 |
LIKE | SELECT col_name1, col_name2 FROM tb1_name WHERE col_name1 LIKE ‘NE’ | 是 | 是 |
通配符 | SELECT col_name1, col_name2 FROM tb1_name WHERE col_name1 LIKE ‘NE%’ | 是 | 是 |
EXISTS | SELECT col_name1, col_name2 FROM tb1_name WHERE EXISTS (expr1) | 是 | 是 |
IN | SELECT col_name1, col_name2 FROM tb1_name WHERE col_name1 IN (expr1, expr2,…) | 是 | 是 |
BETWEEN | SELECT col_name1, col_name2 FROM tb1_name WHERE col_name1 BETWEEN expr1 AND expr2 | 是 | 是 |
ON DUPLICATE | INSERT INTO tb1_name [(col_name,…)] VALUES ({expr | DEFAULT},…),(…),… [ ON DUPLICATE KEY UPDATE col_name=expr, … ] |
是 | 是 |
ALIASES | SELECT t1. col_name1, t2.col_name2 FROM tb1_name AS t1, tb2_name AS t2 WHERE t1. col_name=expr AND t2. col_name=expr |
是 | 是 |
TOP | SELECT TOP 2 * FROM tb1_name | 是 | 是 |
LIMIT | SELECT col_name1, col_name2 FROM tb1_name LIMIT 5 | 是 | 是 |
|
SELECT col_name1, col_name2 FROM tb1_name JOIN tb2_name> ON tb1_name. col_name1= tb2_name. col_name1 |
是 | 否 |
|
SELECT col_name1, col_name2 FROM tb1_name UNION SELECT col_name1, col_name2 FROM tb2_name |
是 | 否 |
函数
下表列出了 DQL 语句和 DML 语句对函数的支持情况,需要注意的是,在 DML 语句中使用函数,不能将其作为主键。
DML 语句支持
类型 | 是否支持 |
---|---|
CONCAT(string2[,…]) | 是 |
INSTR(string,substring) | 是 |
LCASE(string2) | 是 |
LEFT(string2,length) | 是 |
LENGTH(string) | 是 |
LOAD_FILE(file_name) | 是 |
LOCATE(substring,string[,start_position]) | 是 |
LPAD(string2,length,pad) | 是 |
LTRIM(string2) | 是 |
REPEAT(string2,count) | 是 |
REPLACE(str,search_str,replace_str) | 是 |
RPAD(string2,length,pad) | 是 |
RTRIM(string2) | 是 |
STRCMP(string1,string2) | 是 |
SUBSTRING(str,position[,length]) | 是 |
TRIM([[BOTH|LEADING|TRAILING][padding]FROM]string2) | 是 |
UCASE(string2) | 是 |
RIGHT(string2,length) | 是 |
SPACE(count) | 是 |
ABS(number2) | 是 |
BIN(decimal_number) | 是 |
CEILING(number2) | 是 |
CONV(number2,from_base,to_base) | 是 |
FLOOR(number2) | 是 |
FORMAT(number,decimal_places) | 是 |
HEX(DecimalNumber) | 是 |
LEAST(number,number2[,..]) | 是 |
MOD(numerator,denominator) | 是 |
POWER(number,power) | 是 |
RAND([seed]) | 是 |
ROUND(number[,decimals]) | 是 |
SIGN(number2) | 是 |
SQRT(number2) | 是 |
ADDTIME(date2,time_interval) | 是 |
CONVERT_TZ(datetime2,fromTZ,toTZ) | 是 |
CURRENT_DATE() | 是 |
CURRENT_TIME() | 是 |
CURRENT_TIMESTAMP() | 是 |
DATE(datetime) | 是 |
DATE_ADD(date2,INTERVALd_valued_type) | 是 |
DATE_FORMAT(datetime,FormatCodes) | 是 |
DATE_SUB(date2,INTERVALd_valued_type) | 是 |
DATEDIFF(date1,date2) | 是 |
DAY(date) | 是 |
DAYNAME(date) | 是 |
DAYOFWEEK(date) | 是 |
DAYOFYEAR(date) | 是 |
EXTRACT(interval_nameFROMdate) | 是 |
MAKEDATE(year,day) | 是 |
MAKETIME(hour,minute,second) | 是 |
MONTHNAME(date) | 是 |
NOW() | 是 |
SEC_TO_TIME(seconds) | 是 |
STR_TO_DATE(string,format) | 是 |
TIMEDIFF(datetime1,datetime2) | 是 |
TIME_TO_SEC(time) | 是 |
WEEK(date_time[,start_of_week]) | 是 |
YEAR(datetime) | 是 |
DAYOFMONTH(datetime) | 是 |
HOUR(datetime) | 是 |
LAST_DAY(date) | 是 |
MICROSECOND(datetime) | 是 |
MONTH(datetime) | 是 |
MINUTE(datetime) | 是 |
FIRST() | 否 |
LAST() | 否 |
MIN() | 否 |
MAX() | 否 |
AVG() | 否 |
SUM() | 否 |
COUNT() | 否 |
DQL 语句支持
类型 | 读未提交 | 读已提交 |
---|---|---|
CONCAT(string2[,…]) | 是 | 是 |
INSTR(string,substring) | 是 | 是 |
LCASE(string2) | 是 | 是 |
LEFT(string2,length) | 是 | 是 |
LENGTH(string) | 是 | 是 |
LOAD_FILE(file_name) | 是 | 是 |
LOCATE(substring,string[,start_position]) | 是 | 是 |
LPAD(string2,length,pad) | 是 | 是 |
LTRIM(string2) | 是 | 是 |
REPEAT(string2,count) | 是 | 是 |
REPLACE(str,search_str,replace_str) | 是 | 是 |
RPAD(string2,length,pad) | 是 | 是 |
RTRIM(string2) | 是 | 是 |
STRCMP(string1,string2) | 是 | 是 |
SUBSTRING(str,position[,length]) | 是 | 是 |
TRIM([[BOTH|LEADING|TRAILING][padding]FROM]string2) | 是 | 是 |
UCASE(string2) | 是 | 是 |
RIGHT(string2,length) | 是 | 是 |
SPACE(count) | 是 | 是 |
ABS(number2) | 是 | 是 |
BIN(decimal_number) | 是 | 是 |
CEILING(number2) | 是 | 是 |
CONV(number2,from_base,to_base) | 是 | 是 |
FLOOR(number2) | 是 | 是 |
FORMAT(number,decimal_places) | 是 | 是 |
HEX(DecimalNumber) | 是 | 是 |
LEAST(number,number2[,..]) | 是 | 是 |
MOD(numerator,denominator) | 是 | 是 |
POWER(number,power) | 是 | 是 |
RAND([seed]) | 是 | 是 |
ROUND(number[,decimals]) | 是 | 是 |
SIGN(number2) | 是 | 是 |
SQRT(number2) | 是 | 是 |
ADDTIME(date2,time_interval) | 是 | 是 |
CONVERT_TZ(datetime2,fromTZ,toTZ) | 是 | 是 |
CURRENT_DATE() | 是 | 是 |
CURRENT_TIME() | 是 | 是 |
CURRENT_TIMESTAMP() | 是 | 是 |
DATE(datetime) | 是 | 是 |
DATE_ADD(date2,INTERVALd_valued_type) | 是 | 是 |
DATE_FORMAT(datetime,FormatCodes) | 是 | 是 |
DATE_SUB(date2,INTERVALd_valued_type) | 是 | 是 |
DATEDIFF(date1,date2) | 是 | 是 |
DAY(date) | 是 | 是 |
DAYNAME(date) | 是 | 是 |
DAYOFWEEK(date) | 是 | 是 |
DAYOFYEAR(date) | 是 | 是 |
EXTRACT(interval_nameFROMdate) | 是 | 是 |
MAKEDATE(year,day) | 是 | 是 |
MAKETIME(hour,minute,second) | 是 | 是 |
MONTHNAME(date) | 是 | 是 |
NOW() | 是 | 是 |
SEC_TO_TIME(seconds) | 是 | 是 |
STR_TO_DATE(string,format) | 是 | 是 |
TIMEDIFF(datetime1,datetime2) | 是 | 是 |
TIME_TO_SEC(time) | 是 | 是 |
WEEK(date_time[,start_of_week]) | 是 | 是 |
YEAR(datetime) | 是 | 是 |
DAYOFMONTH(datetime) | 是 | 是 |
HOUR(datetime) | 是 | 是 |
LAST_DAY(date) | 是 | 是 |
MICROSECOND(datetime) | 是 | 是 |
MONTH(datetime) | 是 | 是 |
MINUTE(datetime) | 是 | 是 |
FIRST() | 是 | 否 |
LAST() | 是 | 否 |
MIN() | 是 | 否 |
MAX() | 是 | 否 |
AVG() | 是 | 否 |
SUM() | 是 | 否 |
COUNT() | 是 | 否 |
Have fun with Java & 微服务!