将MySQL结果转换为C中的JSON字符串

时间:2014-08-05 17:35:50

标签: mysql c json

如何将结果从MySQL查询转换为C?中的JSON字符串?

当然我知道该怎么做,我只是想知道是否已经有了复制粘贴的解决方案,意识到我不想编写样板代码。

Google如何解决这个问题?谷歌只是忽略c并显示PHP等的结果。

1 个答案:

答案 0 :(得分:0)

我这样做的C文件比相应的PHP文件快四倍,使用ab来衡量性能:

ab -k -c 300 -n 10000 localhost/tiny.php 
Time per request:       393.072 [ms] (mean)

用C:

ab -k -c 300 -n 10000 localhost/cgi/tiny.fcgi
Time per request:       98.237 [ms] (mean)

这假设Apache产生了10个tiny.fcgi进程,PHP不使用FastCGI。

FastCgiServer /var/www/cgi/tiny.fcgi -processes 10

这是PHP代码,它连接到MySQL,获取查询结果并回显JSON表示:

<?php

$mysqli = mysqli_connect("localhost", "user", "password", "db");

mysqli_set_charset($mysqli, "utf8");

if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$result = mysqli_query($mysqli, "SELECT * FROM table");
$rows = array();
while ($row = mysqli_fetch_assoc($result)) {
    $rows[] = $row;
}

echo json_encode($rows);

让我们逐步完成C代码。我将使用PHP内部结构smart_str来处理字符串(这是PHP在json_encode函数中使用的)。对字符串使用天真char*将是灾难性的,因为mallocfree的数量会因字符串附加用法而变得很大。

我们想使用FastCGI:

#include "fcgi_stdio.h"

int main(void)
{
  while(FCGI_Accept() >= 0)
  {
  }
  FCGI_Finish();
  return 0;
}

使用valgrind进行分析,结果仍然可以得到768个字节,我们将忽略它(可能是FastCGI中的错误)。

接下来是MySQL连接和查询:

MYSQL*  connection = NULL;
MYSQL_RES* result = NULL;

connection = mysql_init(NULL);

if (connection == NULL)
{
  (void) FCGI_fprintf(FCGI_stderr, "Could not connect to MySQL: %s\n", mysql_error(connection));
  continue;
}

// Connect to database
if (mysql_real_connect(connection, "localhost", "user", "password", "db", 0, NULL, 0) == NULL) 
{
  close_mysql_with_error(connection);
  continue;
}

// Select from pages
if (mysql_query(connection, "SELECT * FROM table") != 0)
{
  close_mysql_with_error(connection);
  continue;
}

// Get result
result = mysql_store_result(connection);

// Abort if no result
if (result == NULL)
{
  close_mysql_with_error(connection);
  continue;
}

(我使用continue代替exitreturn,因为此代码位于上面显示的while循环中。)

这里没什么奇怪的,对吧?

下一部分将创建我们的smart_str JSON变量,将其传递给函数result_to_json,然后回显结果。

smart_str json = {0, 0, 0};
result_to_json(result, &json);
if (json.c != NULL)
  (void) FCGI_printf("json = %s\n", json.c);
smart_str_free(&json);

result_to_json只是MySQL结果中行的循环:

static void result_to_json(MYSQL_RES *result, smart_str* json)
{

  MYSQL_ROW row;

  int i;
  int num_fields = (int) mysql_num_fields(result);
  smart_str** fields = get_field_names(result, num_fields);

  if (fields == NULL)
  {
    return;
  }

  smart_str_appendc(json, '[');

  while ((row = mysql_fetch_row(result, num_fields)))
  {
    smart_str_appendl(json, "{", 1);

    for (i = 0; i < num_fields; i++)
    {
      // key
      smart_str_appendl(json, "\"", 1);
      smart_str_appendl(json, fields[i]->c, fields[i]->len);
      smart_str_appendl(json, "\": ", 3);

      if (row[i] == NULL)
      {
        smart_str_appendl(json, "null", 4);
        smart_str_appendl(json, ", ", 2);
      }
      else
      {
        smart_str_appendl(json, "\"", 1);
        smart_str_appendl(json, row[i], strlen(row[i]));
        smart_str_appendl(json, "\", ", 3);
      }

    }

    if (json == NULL) {
      free_field_names(fields, num_fields);
      return;
    }

    // Strip last ','
    json->len--;
    json->len--;

    smart_str_appendl(json, "}, ", 3);
  }

  if (json == NULL)
  {
    free_field_names(fields, num_fields);
    return;
  }

  // Strip last ','
  json->len--;
  json->len--;

  smart_str_appendl(json, "]", 1);
  smart_str_0(json);

  free_field_names(fields, num_fields);

  return;
}

最后,get_field_namesfree_field_names

static smart_str** get_field_names(MYSQL_RES *my_result, int num_fields)
{
  smart_str** fields;   // Array of pointers
  MYSQL_FIELD *field = NULL;
  int i;

  // Allocate size of array
  fields = malloc(num_fields * sizeof(smart_str*));

  if (fields == NULL) 
  {
    return NULL;
  }

  for (i = 0; i < num_fields; i++)
  {
    field = mysql_fetch_field(my_result);

    if (field == NULL) {
      // TODO: Free fields[]
      free(fields);
      return NULL;
    }

    fields[i] = malloc(sizeof(smart_str));

    if (fields[i] == NULL) {
      // TODO: Free fields[]
      free(fields);
      return NULL;
    }
    else 
    {
      fields[i]->c = NULL;
      smart_str_appendl(fields[i], field->name, strlen(field->name));
    }

  return fields;

}

static void free_field_names(smart_str** strings, int size)
{

  int i;
  for (i = 0; i < size; i++)
  {
    smart_str_free(strings[i]);
    free(strings[i]);
  }

  free(strings);

}
你去吧!剩下的工作就是针对启用了FastCGI的PHP进行测量,以了解PHP性能提高了多少。