【发布时间】:2019-05-18 20:12:42
【问题描述】:
我有 Percona Mysql 服务器和带有自定义 ORM 的 Java 客户端。在数据库中我有表:
CREATE TABLE `PlayerSecret` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`created` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`secret` binary(16) NOT NULL,
`player_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `PlayerSecret_secret_unique` (`secret`),
KEY `PlayerSecret_player_id` (`player_id`)
) ENGINE=InnoDB AUTO_INCREMENT=141 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
我找到了那个查询SELECT PlayerSecret.player_id FROM PlayerSecret WHERE PlayerSecret.secret = ?
当java.sql.PreparedStatement#setBytes 方法提供参数时,返回一个空结果集,并且通过java.sql.PreparedStatement#setBinaryStream 按预期工作。我启用了 mysql 常规日志,发现在这个日志中两个查询是相同的,我在十六进制模式下检查了这个。
一般日志看起来像:
SELECT PlayerSecret.player_id FROM PlayerSecret WHERE PlayerSecret.secret = '<96>R\Ø8üõA\í¤Z´^E\Ô\ÊÁ\Ö'
从普通日志以十六进制模式查询参数:
2796 525c d838 fcf5 415c eda4 5ab4 055c d45c cac1 5cd6 27
数据库中的值:
mysql> select hex(secret) from PlayerSecret where id=109;
+----------------------------------+
| hex(secret) |
+----------------------------------+
| 9652D838FCF541EDA45AB405D4CAC1D6 |
+----------------------------------+
1 row in set (0.00 sec)
问题是我的 ORM 通过 setBytes 方法执行此查询,我认为这是 BINARY 数据类型的正确方法,但它不起作用。
my.cnf 的一部分,带有编码设置(也许很重要):
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
general_log = on
general_log_file=/var/log/mysql/mysqld_general.log
require_secure_transport = ON
init-connect = SET collation_connection = utf8mb4_unicode_ci
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
Java 代码:
var uuid = UUID.fromString("9652d838-fcf5-41ed-a45a-b405d4cac1d6");
var array = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
// works
stmt.setBinaryStream(index, new ByteArrayInputStream(array));
// don't works
stmt.setBytes(index, array);
我不明白这两种情况有什么区别,以及如何解决setBytes 变体的问题。
也许有人可以澄清这一点或向我指出重要的部分/地方?
我的环境:
- OpenJDK 11
- HicariCP 3.1.0
- MySQL 连接器/J 8.0.13
- Percona 5.7.24-26-log Percona Server (GPL),Release '26',Revision 'c8fe767'
【问题讨论】:
-
显示你使用
setBytes和setBinaryStream的代码。我们不知道您从哪里获取字节以及如何操作它们。 -
@RealSkeptic 添加了,但由于两个查询在一般日志中是相同的 - 这是否意味着差异应该在查询元数据或任何其他地方?
-
您的常规日志中可能有隐藏字符。我可以看到,通用日志中的十六进制与数据库中的十六进制不匹配。最好提供minimal reproducible example。
-
是的,我也发现了这个 - 它包含转义某些字节的反斜杠,我认为二进制数据很奇怪(可能在写入一般日志时发生转义)......但它适用于他们,我不知道我应该在哪里寻找这种行为的原因。
标签: java mysql jdbc percona connector-j