【问题标题】:Inserting an array of 16-bit ints to MySQL, from C从 C 向 MySQL 插入一个 16 位整数数组
【发布时间】:2014-12-22 02:50:37
【问题描述】:

我需要将大量 int16_t 放入 MySQL 数据库中。我通过将值复制到 char 缓冲区来构造一个查询字符串,但最终它不起作用(char 是 1 个字节,int16_t 是两个字节。)我在网上找到的关于将数组插入 MySQL 的文档是这样做的使用字符数组。

如何将这个 int16_t 数组插入 MySQL 数据库?

【问题讨论】:

  • 不要复制到“字符缓冲区”,创建一个查询字符串。包含大量UPDATEINSERT SQL 语句的字符串。
  • @JoachimPileborg - 但是循环和更新数千次只是为了将一行插入数据库不是一个坏主意吗?我正在处理实时数据..
  • 你不能用UPDATE插入行,那是不可能的。

标签: mysql c


【解决方案1】:

我认为您应该查看 BLOB 数据类型。它可以将二进制数据块存储到列中。有4种不同的口味,根据你需要的大小。请看以下示例,其中图像存储在数据库中:

http://zetcode.com/db/mysqlc/

真正有趣的部分是页面中大约 80% 的位置,其中存储了图像,然后从数据库中检索图像。特别注意 mysql_real_escape_string() 函数,它确保数据对于实际查询是合法的。您应该可以立即发送 int16 数组。

编辑...这是有效的“保存”路由。它保存整数数组 作为二进制 blob 进入数据库。这个程序不完整。例如。它没有连接到数据库,

#define SIZE 20000
int16_t ints[SIZE];

MYSQL *con;

int
ints_saved(void) // Returns 0 if there's an error
{
  char   *chunk, *st, *query;
  size_t ints_size = sizeof(ints), 
         st_len;
  int qlen;

  chunk = (char *)malloc(ints_size*2 + 1);
  // template for creating SQL
  st = "insert into Ints(Id, Data) values(1, '%s')"; 
  st_len = strlen(st);

  // Remove dangerous characters
  mysql_real_escape_string(con, chunk, (char *)ints, ints_size);

  query = (char *)malloc(st_len + 2*ints_size+1);
  // Construct the actual query here
  qlen = snprintf(query, st_len + 2*ints_size+1, st, chunk);

  printf("%s\n", query);
  // Execute the query
  if (mysql_real_query(con, query, qlen)) {
    printf("%s\n", mysql_error(con));
    return(0);
  };

  return(1);
}

请注意,数据库表是用两列定义的,Id(int) 和 Data(blob)。如果您有其他大小要求,您可能需要修改 blob。

警告:还没有人大声喊叫,但请注意这个系统可能会在不同的编译器中产生不同的结果。一些编译器可能会将 16 位整数与 4 字节边界对齐。因此,虽然我已经在 sizeof() 函数中考虑到了这一点,但实际保存的记录可能会在某些机器上占用更多空间。如果您想避免这个问题,您可以使用“打包”记录来避免这种情况 - 请参阅编译器的文档。

write 过程:int16_t 在一个数组中。如果我将其视为整数,我会得到:

17767 9158 -26519 18547 -9135 23807 -27574 22764 7977 31949 22714 -10325 16882 7931 -22045 -7866 124 25282 2132 10232 8987 -5656 -12825 17293

查看与字节(或字符)相同的数组,我明白了:

67 45 C6 23 69 98 73 48 51 DC FF 5C 4A 94 EC 58 29 1F CD 7C BA 58 AB D7

(67 45是第一个int值,17767)

我不能写这个,因为字节 11 是 0x5C,这混淆了查询字符串:

67 45 C6 23 69 98 73 48 51 DC FF 5C 4A 94 EC 58 29 1F CD 7C BA 58 AB D7  
                                 ^^

所以,我调用了 mysql_escape 函数,并使用结果来形成查询:

67 45 c6 23 69 98 73 48 51 dc ff 5c 5c 4a 94 ec 58 29 1f cd 7c ba 58 ab 
                                 ^^^^^

注意到多余的 0x5c 了吗?

当我执行查询时,我将转义字符串发送到 MySQL,然后 MySQL 立即 删除转义并将 UN-ESCAPED 字符串写入数据库。所以,从现在开始,哪里不再有多余的 0x5c 字符了。如果你读回来,数据又是“纯”的。

一个非常简约的例子。假设我只想将一个 0x5c 写入表:

我不能写:insert into Ints(Id, Data) values (1, '\') 因为 MySQL 会认为我在 \ 之后转义了 '。 (记住 '\' 是 0x5c)

所以我逃脱了那个\:insert into Ints(Id, Data) values (1, '\\')。当 MySQL 收到这个查询时,它只插入 one \。

在表格中只插入了一个字符。回读时,它只产生一个字符。

【讨论】:

  • 根据我之前给你的链接中的指示,编辑了上面的答案以包括实际工作的代码,它可以满足你的需要。
  • Yes... 0x5c 是转义字符(不是 ASCII ESC 字符,而是反斜杠)。如果您检查转义的 qyery 中的下一个字符,您会发现“危险”字符,例如反斜杠本身。不过没关系。实际写入记录的数据没有这些 0x5c。它们只是为了让查询安全地到达 MySQL。
  • 你怎么知道转义符在 blob 中? 0x5c 可以是有效的整数值。我对 20000 个值进行了测试,并为所有整数分配了随机值。使用 phpMyAdmin(实际上,保存为来自 MyAdmin 的二进制文件,因为它没有 blob 查看器)时,生成的 blob 是 正好 40000 字节长 - 所以没有额外的字节。你如何读取数据?您使用哪种引擎? (我用的是 InnoDB)下一个字节的值是多少?
  • 你能分享那个代码吗?您说“数据库数据匹配”,但您究竟是如何从数据库中读取数据的。而且您不会在阅读时调用 mysql_real_escape_string() 函数吗?那是不正确的。
  • 再一次,在阅读时,没有什么可以摆脱的。数据库中的数据不包含任何转义。当然,它可以包含反斜杠,但这些反斜杠是原始数据的一部分。
猜你喜欢
  • 2016-03-11
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多