huixiang
(huixiang)
2025 年7 月 1 日 10:24
1
【TiDB 使用环境】生产环境
【TiDB 版本】7.5
【操作系统】Centos7.9
【问题复现路径】TIDB版本原地版本5.1升级到7.5.3
【遇到的问题:问题现象及影响】
1)TIDB版本升级前5.1版本时, java代码中使用的是mysql5.1.42版本的驱动,ext_json->>‘%xxx’取出来的就是值(字符串或数字),但是访问升级后的7.5,取出来的结果是byte类型,导致代码逻辑变化。
2)研发尝试使用新的mysql驱动(8.0.33)来解决兼容问题,但是ext_json->>’%xxx’结果也byte类型。
求助问题:
**1)问题原因?**是TIDB升级后对json的处理不同了么?
2)简便的快速回滚方法。
因为此TIDB集群有很多java应用使用,逐个修改代码逻辑工作量较大。研发希望可快速回滚到原来的状态(ext_json->>‘%xxx’)结果是值,请问是否有好的方法?
【资源配置】
【复制黏贴 ERROR 报错的日志】
【其他附件:截图/日志/监控】
huixiang
(huixiang)
2025 年7 月 1 日 10:31
2
使用Python, 及原生的mysql 客户端,查询TiDB5.1/TIDB7.5结果都是相同的,不存在研发反馈的问题。
MySQL:
Python:
SQL="SELECT ‘10.8.5’ AS se_version,‘0’ AS se_city,a.modified_stime,‘business’ AS se_business_type,a.ext_json ->>‘$.data_type’ as data_type FROM tb_car_pool a LEFT JOIN resource_pool_merge.uniq_nlp_tags e ON a.object_uid=e.object_uid WHERE a.object_uid=‘52-4-656181’ AND a.recommend_used=1 AND a.biz_type=52 AND a.is_delete=0 AND e.object_uid IS NOT NULL AND a.recommend_time IS NOT NULL AND a.recommend_time<=CURRENT_TIMESTAMP AND date_add(CURRENT_TIMESTAMP,INTERVAL-30 DAY)< a.recommend_time "
cursor1.execute(SQL)
rows1 = cursor1.fetchone()
cursor2.execute(SQL)
rows2 = cursor2.fetchone()
rows1
{u’se_business_type’: u’business’, u’se_version’: u’10.8.5’, u’data_type’: u’1’, u’se_city’: u’0’, u’modified_stime’: datetime.datetime(2025, 6, 30, 17, 31, 45)}
rows2
{u’se_business_type’: u’business’, u’se_version’: u’10.8.5’, u’data_type’: u’1’, u’se_city’: u’0’, u’modified_stime’: datetime.datetime(2025, 6, 30, 17, 31, 45)}
有猫万事足
2025 年7 月 2 日 04:28
5
https://docs.pingcap.com/zh/tidb/v5.4/system-variables/#version
在5.1的时候,version字段是5.7.25-TiDB-(tidb version),也就是tidb会被驱动识别为5.7.25版本的mysql。
https://docs.pingcap.com/zh/tidb/v7.5/system-variables/#version
在7.5的时候,version字段是 8.0.11-TiDB-(tidb version),也就是驱动识别tidb为mysql 8.0.11。
我怀疑是这个地方让驱动识别的mysql版本发生了变化,然后就导致了你现在的问题。
你尝试使用新的mysql驱动也没解决,是因为新驱动识别出来的msyql版本还是8.0.11。
我感觉你可以把这个地方改回5.7.25-TiDB-(tidb version)这种格式。看看问题是否已经解决。
huixiang
(huixiang)
2025 年7 月 3 日 02:56
6
https://docs.pingcap.com/zh/tidb/v7.5/system-variables/#version
version
作用域:NONE
是否受 Hint SET_VAR 控制:否
默认值:8.0.11-TiDB-(tidb version)
这个变量的值是 MySQL 的版本和 TiDB 的版本,例如 ‘8.0.11-TiDB-v7.5.6’。
==
version 好象是一个只读参数,无法修改。
WalterWj
(王军 - PingCAP)
2025 年7 月 3 日 03:06
7
1 个赞
huixiang
(huixiang)
2025 年7 月 3 日 03:26
8
多谢,这种select version()是版本变了。
select version();
±-------------------+
| version() |
±-------------------+
| 5.7.25-TiDB-v5.1.4 |
±-------------------+
1 row in set (0.00 sec)
配置:
server_configs:
tidb:
binlog.enable: false
server-version: 5.7.25-TiDB-v5.1.4
huixiang
(huixiang)
2025 年7 月 8 日 06:22
10
1)有类似事件
已打开 12:50PM - 29 Aug 22 UTC
已关闭 07:18AM - 31 Aug 22 UTC
type/enhancement
component/json
## Enhancement
In the mysql 5.7 `mysql-server/sql/item.cc: Item::save_in_fiel… d_inner`, it transformed the JSON into the string, and stored it in the field:
```cpp
String *result;
const CHARSET_INFO *cs= collation.collation;
char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
str_value.set_quick(buff, sizeof(buff), cs);
result=val_str(&str_value);
if (null_value)
{
str_value.set_quick(0, 0, cs);
return set_field_to_null_with_conversions(field, no_conversions);
}
/* NOTE: If null_value == FALSE, "result" must be not NULL. */
field->set_notnull();
type_conversion_status error=
field->store(result->ptr(),result->length(),
field->type() == MYSQL_TYPE_JSON ? result->charset() : cs);
str_value.set_quick(0, 0, cs);
return error;
```
During this procedure, the opaque information is lost, the MySQL cannot distinguish the opaque value and string value anymore. It causes the confusing behavior:
```sql
create table test (a json);
insert into test select json_objectagg('a', b'01010101');
select json_type(json_extract(a, '$.a')); -- returns STRING
select json_type(json_extract(json_object('a', b'01010101'), '$.a')); -- returns BIT
```
Through the two json values are constructed in the same way, they have different behavior before and after storing to the disk. This confusing behavior results in the incompatibility of following SQLs:
```sql
create table test (a json);
insert into test select json_objectagg('a', b'01010101');
select * from test where json_extract(a, '$.a') = "base64:type16:VQ==";
```
TiDB gives empty set (as the json opaque is never equal with the json string), but MySQL will give the inserted row. Instead, consider the following example:
```sql
create table test (a json);
insert into test select json_objectagg('a', b'01010101');
select * from test where json_extract(a,'$.a') = json_extract(json_object('a', b'01010101'), '$.a');
```
The TiDB will give a row, but the MySQL will not. (After fixing the problems in https://github.com/pingcap/tidb/issues/37435, because this function will also lose the charset / collate information :cry: )
I don't know whether we should be compatible with MySQL in this case, because the current behavior (after fixing #37435) of TiDB sounds much more reasonable.
2)研发改代码解决的。
Map<String, Object> item = Maps.newHashMap();
for(Map.Entry<String,Object> entry: item1.entrySet()){
String key = entry.getKey();
Object value = entry.getValue();
if (value != null && value instanceof byte ){
value = new String((byte ) value, StandardCharsets.UTF_8);
}
item.put(key,value);
}
1 个赞