前言
C++实现的业务系统已经支持MYSQL版本,本次改造主要适配DRDS(介绍见DRDS应用开发指南)。DRDS兼容MYSQL语法,适配起来很方便。DRDS本身不提供C++的客户端,本次使用社区版MYSQL客户端。对于DRDS涉及基本的SQL操作,无需改造就可以运行。有些特殊的使用方法需要单独处理,实录如下:
问题及处理思路
1. MYSQL/DRDS兼容处理
本次改造直接使用MYSQL封装的DBC来支持SQL操作。如果存在差异,提供单独接口。在业务侧,构造数据库链接时,根据配置来指定数据库类型MYSQL/DRDS。不兼容的SQL,在业务侧根据数据库类型执行不同条件分支来实现。
2. stmt 不支持 DROP/CREATE
问题描述:以前MYSQL的DBC封装采用stmt以提高性能。使用stmt来执行DROP/CREATE的SQL语句时,会提示语法错误(1064)。
错误信息问题分析:MYSQL的官网信息Error: 1064 SQLSTATE: 42000 (ER_PARSE_ERROR)Message: %s near '%s' at line %d。参与资料《MySQL 的 C API预处理语句》,猜测应该服务端不支持stmt方式执行DROP/CTRATE。【1064是通用错误? 】
解决思路:
1)技术验证mysql_query方式可以执行DROP/CREATE语句。
2)使用mysql_query方式实现一套区别于stmt接口,对于报错语句在DRDS下使用新接口执行。
3. DROP/CREATE的跨库事务问题
问题描述:MYSQL的DBC封装时通过mysql_autocommit来关闭自动提交,由应用统一来控制事务提交。在这种场景下执行DROP/CREATE操作分库表,会报以下错误:
TDBException: ERROR_MSG=TDBException: [c7622f788c01000-4][10.135.237.68:3306][cc]ERR-CODE: [TDDL-4603][ERR_ACCROSS_DB_TRANSACTION] Transaction accross db is not supported in current transaction policy, transaction node is: CC_1515572409568KAQTCC_SSYA_0000_RDS, but this sql execute on: CC_1515572409568KAQTCC_SSYA_0008_RDS. More: [http://middleware.alibaba-inc.com/faq/faqByFaqCode.html?faqCode=TDDL-4603]. you can use 'show warnings' for more detail message.
问题分析:DRDS的官网信息对该错误进行详尽描述。对于DROP/CREATE,如果mysql_autocommit是自动提交,DROP/CREATE操作跨库表,可以正确执行。
解决思路:一般情况下,一个业务程序只使用一个数据库链接,mysql_autocommit设置手动提交在连接初期就确定好了,为了防止影响别的SQL,不能直接修改链接的事务方式。在执行DROP/CREATE函数里面,调用mysql_query之前,通过mysql_autocommit设置自动提交;之后恢复数据库链接提交方式。
通过2,3方法,解决对垮库表CREATE/DROP操作。
4. stmt 不支持特殊SELECT语句
问题描述: 在业务验证时,stmt不支持特殊的SELECT,如下
支持:
SELECT DISTINCT CONCAT(A,B,'C',D) CREATE_SQL FROM TABA WHERE A='A' AND B='B'
不支持:
SELECT 1 FROM TABLE_NAME
SELECT FILE_ID_SEQ..NEXTVAL SEQ_VALUE FROM DUAL
SELECT FILE_ID_SEQ.NEXTVAL SEQ_VALUE
使用stmt方式执行时,报类似2的错误。
解决思路:同2,使用mysql_query来实现一套单独接口。特别的,SELECT对于事务性没有要求,即使手动提交也可以执行。
5. 表不存在的返回码问题
问题描述:利用SELECT 1 FROM TABLE_NAME来检测表不存在。MYSQL的错误码是1146。即Error: 1146 SQLSTATE: 42S02 (ER_NO_SUCH_TABLE)。而DRDR使用mysql_errno错误码1064,并且包含一个TDDL-4007。客户端与C++显示错误信息一致。
使用Navicate查询表不存在的错误信息解决思路:对于DRDS,当判断表不存在时,错误码是1064(感觉像个通用错误码?)。需要从错误信息里判断TDDL-4007来确认表不存在。
通过4和5,SELECT 1 FROM TABLE_NAME来判断表不存在搞定。
6.
DRDS提供SIMPLE序列返回类型问题
问题描述:DRDS提供SIMPLE序列和BIGINT字段返回类型都是8(MYSQL_TYPE_LONGLONG longlong)但是buffer里面数值格式不一致,SIMPLE序列返回时字符串格式,BIGINT字段返回long long整形格式。(MYSQL的MYSQL_TYPE_LONGLONG是long long整形格式)
解决思路:对于DRDS,提供一个单独接口专门处理DRDS提供SIMPLE序列返回值问题。
通过4和6,可以搞定序列取值问题。
7.
stmt方式执行insert时偶尔失败问题
问题描述:C++程序有个insert语句有时候成功,有时候不成功。问题出在varchar(255),文件名是字符串时候就有问题,改成数字就可以了。一开始怀疑是字符集,设置为UTF8也有类似问题。
INSERT INTO EVENT_FILELIST (FILE_ID, FILE_NAME, FILE_SIZE, CREATED_DATE, STATE, STATE_DATE, RATING_FLOW_ID,EVENT_SRC_ID) VALUES ( ?, ?, ?, STR_TO_DATE( ?,'%Y%m%d%H%i%S'), ?, STR_TO_DATE( ?,'%Y%m%d%H%i%S'), ?, ?) 2018-02-09 16:54:34 [DETAIL] > CCBS:Get Exception:File[/home/v90ocs1/src90/billing/proc/TGatherFileOper.cpp] Line[194] Exception Message=TDBException: ERROR_MSG=TDBException: TDBQuery::Execute() mysql_stmt_execute failed. errno:4998, errmsg:[c78e06d11800000-37d][10.135.236.60:3306][cc]ERR-CODE: [TDDL-4998][ERR_NOT_SUPPORT] parameter of mysqltype:-32514 fullblob:false encode:latin1 not support yet! More: [http://middleware.alibaba-inc.com/faq/faqByFaqCode.html?faqCode=TDDL-4998]
解决思路:同事走查代码发现缺少memset,MYSQL的dbc封装存在缺陷。MYSQL下无问题,DRDS存在问题。
缺少memset8. set方式支持存在部分问题
C++应用适配DRDS小结小结
本次C++主要解决查询并自动建表,以及获取序列等功能。DRDS提供额外特性,可以满足特许需求,也存在和MYSQL的语法差异。需要做一些特殊来解决这些问题。
网友评论