Go+MySQL中如何在预处理语句WHERE子句使用JSON_EXTRACTOR?
问题描述
我有如下表结构:
CREATE TABLE IF NOT EXISTS test_table ( id CHAR(36) NOT NULL, json JSON, PRIMARY KEY (id) ) ENGINE=InnoDB;
我希望基于json字段的内容过滤SELECT查询。使用Go语言结合sqlx(扩展golang/sql)编写了如下代码:
query := "SELECT * FROM test_table WHERE json->'$.alive' = ?" rows, err := db.QueryxContext(ctx, query, true) if err != nil { fmt.Println(err) } defer rows.Close() for rows.Next() { var id int var json string rows.Scan(&id, &json) }
该代码返回空结果集,但在DataGrip中执行相同逻辑的查询能得到预期结果。我已在最简复现环境中测试,问题仍存在且无报错。
目前我可以通过拼接SQL语句(如query := "SELECT * FROM test_table WHERE json->'$.alive' = true")绕过,但希望避免这种方式。我尝试过传入字符串"true"、数字1(因MySQL底层用TINYINT存储布尔值)以及完整写法JSON_EXTRACT,均无效,恳请提供帮助。
环境信息:
- go1.19.11 linux/amd64
- mysql8.0.33 for Linux on x86_64
- github.com/go-sql-driver/mysql v1.6.0
- github.com/jmoiron/sqlx v1.3.5
解决办法
核心问题是MySQL对JSON布尔值的类型匹配规则:参数化查询时,Go驱动会把布尔值true转为MySQL的TINYINT(1)类型,但json->'$.alive'返回的是JSON原生布尔类型,两者类型不匹配导致查询无结果。以下是几种可行的解决方式:
1. 强制将参数转为JSON类型
通过CAST(? AS JSON)把传入的字符串参数转为JSON布尔值,和JSON字段提取出的值做类型匹配:
query := "SELECT * FROM test_table WHERE json->'$.alive' = CAST(? AS JSON)" rows, err := db.QueryxContext(ctx, query, "true")
或者使用MySQL的JSON_EQUAL函数,它会忽略类型差异直接比较JSON值:
query := "SELECT * FROM test_table WHERE JSON_EQUAL(json->'$.alive', ?)" rows, err := db.QueryxContext(ctx, query, "true")
2. 使用->>操作符提取字符串值
->>会将JSON值直接转为字符串类型,此时传入字符串"true"即可匹配:
query := "SELECT * FROM test_table WHERE json->>'$.alive' = ?" rows, err := db.QueryxContext(ctx, query, "true")
3. 修复Scan时的类型错误
你的代码中存在一个隐藏问题:表结构里id是CHAR(36)(UUID类型),但你用int类型接收,这会导致Scan失败(只是未处理错误所以没发现)。应将id改为string类型:
for rows.Next() { var id string var jsonStr string if err := rows.Scan(&id, &jsonStr); err != nil { fmt.Println(err) continue } // 处理数据逻辑 }
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

