canal 版本1.0.24 写入MySQL的JSON数据,Canal解析失败
2017-06-22 11:39:25.104 [destination = example , address = /127.0.0.1:3306 , EventParser] ERROR com.alibaba.otter.canal.common.alarm.LogAlarmHandler - destination:example[com.alibaba.otter.canal.parse.exception.CanalParseException: com.alibaba.otter.canal.parse.exception.CanalParseException: parse row data failed. Caused by: com.alibaba.otter.canal.parse.exception.CanalParseException: parse row data failed. Caused by: java.lang.IllegalArgumentException: illegal json data at com.taobao.tddl.dbsync.binlog.JsonConversion.parse_array_or_object(JsonConversion.java:81) at com.taobao.tddl.dbsync.binlog.JsonConversion.parse_value(JsonConversion.java:61) at com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.fetchValue(RowsLogBuffer.java:955) at com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.nextValue(RowsLogBuffer.java:99) at com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert.parseOneRow(LogEventConvert.java:495) at com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert.parseRowsEvent(LogEventConvert.java:376) at com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert.parse(LogEventConvert.java:108) at com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert.parse(LogEventConvert.java:62) at com.alibaba.otter.canal.parse.inbound.AbstractEventParser.parseAndProfilingIfNecessary(AbstractEventParser.java:326) at com.alibaba.otter.canal.parse.inbound.AbstractEventParser$3$1.sink(AbstractEventParser.java:176) at com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection.dump(MysqlConnection.java:130) at com.alibaba.otter.canal.parse.inbound.AbstractEventParser$3.run(AbstractEventParser.java:209) at java.lang.Thread.run(Thread.java:745)
另外如果json中包含双引号,canal解析之后丢失了转义符号。
两个问题,第一个问题还没找到出问题的SQL, 第二个是canal已经解析了,并且canal client可以拿到数据。
+-------+-------------+------+-----+-------------------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+-------------------+-------+ | id | int(11) | NO | PRI | NULL | | | dt | timestamp | NO | | CURRENT_TIMESTAMP | | | json1 | json | YES | | NULL | | | aa | varchar(50) | YES | | NULL | | +-------+-------------+------+-----+-------------------+-------+
insert into t1(id, json1, aa) values(3,"{"test":"aa\"aa"}", "a");
查回来是这样的 +----+---------------------+--------------------+------+ | id | dt | json1 | aa | +----+---------------------+--------------------+------+ | 3 | 2017-06-22 14:34:19 | {"test": "aa"aa"} | a | +----+---------------------+--------------------+------+ canal client取出的json如图。 变成了{"test":"aa"aa"}。
原提问者GitHub用户toruneko
首先需要确认一下MySQL5.7的JSON解析器是否支持该JSON格式,可以使用以下命令检查:
SELECT JSON_UNQUOTE(json_data) FROM table WHERE id = 1;
如果返回的结果与原JSON格式一致,则说明解析器能够正常解析JSON数据。如果返回的结果与原JSON格式不同,则需要升级MySQL5.7的JSON解析器或者使用其他方式处理JSON数据。
Canal解析JSON数据时会自动将双引号进行转义,如果在MySQL中存储的数据包含双引号,则可能导致解析后的数据丢失双引号。可以考虑在写入MySQL数据时使用REPLACE函数将双引号替换为反斜杠(),例如:
INSERT INTO table (id, json1, aa) VALUES (3, replace(json_data, '"', '\'), 'a');
另外,建议在查询MySQL数据前先对数据进行编码和解码,避免出现乱码问题。例如:
SELECT CONCAT(CAST(json_data AS CHAR), '{}') AS decoded_data FROM table WHERE id = 1;
找到导致illegal json data 的SQL了。 json大概有25000个字节,就补贴出来了。
会不会是因为json太大,导致bytes和len长度计算错误。
原回答者GitHub用户toruneko
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。