You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Rust sqlx查询MySQL时,VARBINARY(16)列作为WHERE条件无返回行

使用Rust sqlx查询MySQL VARBINARY(16)字段的正确方式

我用Rust的sqlx库查询MySQL表,其中machine_id字段是VARBINARY(16)类型,表结构如下:

mysql> desc machine_state;
+------------+-----------------+------+-----+---------+-------+
| Field      | Type            | Null | Key | Default | Extra |
+------------+-----------------+------+-----+---------+-------+
| id         | binary(16)      | NO   | PRI | NULL    |       |
| data       | varbinary(2048) | YES  |     | NULL    |       |
| machine_id | varbinary(16)   | NO   |     | NULL    |       |
+------------+-----------------+------+-----+---------+-------+

在MySQL命令行中,通过UNHEX函数可以正常查询到数据:

mysql> SELECT * from machine_state where machine_id = UNHEX('b25c07f2d2904704b7921173915c62ea');
+------------------------------------+------------+------------------------------------+
| id                                 | data       | machine_id                         |
+------------------------------------+------------+------------------------------------+
| 0x00002422C9CF4D8BB8D44941D4DE66B7 | 0x0100     | 0xB25C07F2D2904704B7921173915C62EA |
+------------------------------------+------------+------------------------------------+
1 row in set (0.00 sec)

但使用sqlx尝试多种方式均返回Ok(None),无报错但无法获取记录:

// Input variable I am looking for in a binary column
let machine_id = "b25c07f2d2904704b7921173915c62ea";

// Try using UNHEX with a bind variable
let query_result = sqlx::query::<_>("SELECT * from machine_state where machine_id = UNHEX(?)")
  .bind(machine_id)
  .fetch_optional(database_connection_pool).await;

println!("{:?}", query_result);

// Try using UNHEX directly as in the command line    
let query_result = sqlx::query::<_>("SELECT * from machine_state where machine_id.as_bytes = UNHEX('b25c07f2d2904704b7921173915c62ea')")
  .fetch_optional(database_connection_pool).await;

println!("{:?}", query_result);

// Try binding a Vec<u8> representation of the string
let bytes: Vec<u8> = machine_id.as_bytes().to_vec();

let query_result = sqlx::query::<_>("SELECT * from machine_state where machine_id = ?")
        .bind(bytes)
        .fetch_optional(database_connection_pool).await;

println!("{:?}", query_result);

// OUTPUT ....
// Ok(None)
// Ok(None)
// Ok(None)

问题分析

你的尝试存在两个核心问题:

  1. 十六进制字符串未正确解码:第三种方式中,machine_id.as_bytes()获取的是字符串每个字符的ASCII字节(比如"b"对应0x62,"2"对应0x32),而非十六进制字符串解码后的16字节二进制数据,和数据库中存储的VARBINARY(16)值不匹配。
  2. UNHEX绑定的类型问题:第一种方式中,sqlx会将字符串参数按MySQL字符串类型处理,可能因转义或类型转换导致UNHEX无法正确解析原始十六进制字符串。

正确解法

需要先将十六进制字符串解码为对应的二进制字节,再绑定到查询参数:

  1. 添加依赖:在Cargo.toml中引入hex crate用于十六进制解码:
[dependencies]
hex = "0.4"
sqlx = { version = "0.7", features = ["mysql", "runtime-tokio-native-tls"] }
# 根据你的运行时调整sqlx的features
  1. 解码并查询:
use hex;

// 原始十六进制字符串
let machine_id_hex = "b25c07f2d2904704b7921173915c62ea";

// 将十六进制字符串解码为二进制字节(注意处理解码错误)
let machine_id_bytes = hex::decode(machine_id_hex).expect("Invalid hexadecimal string");

// 确保解码后的字节长度为16,匹配VARBINARY(16)的定义
assert_eq!(machine_id_bytes.len(), 16, "Machine ID must be 16 bytes");

// 使用sqlx查询,绑定二进制数据
let query_result = sqlx::query::<_>("SELECT * from machine_state where machine_id = ?")
    .bind(machine_id_bytes)
    .fetch_optional(database_connection_pool)
    .await;

println!("{:?}", query_result);

如果使用sqlx的宏查询(需要启用macros feature),可以这样写:

let query_result = sqlx::query!("SELECT * from machine_state where machine_id = ?", machine_id_bytes)
    .fetch_optional(database_connection_pool)
    .await;

额外注意事项

  • 必须保证解码后的字节长度为16,否则无法匹配VARBINARY(16)字段的存储值。
  • 若不想引入hex crate,可手动实现十六进制字符串解码,但使用成熟的库更可靠且不易出错。

内容的提问来源于stack exchange,提问作者SantaCruzDeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 00:05:21