【问题标题】:mysql reconnect c++mysql重新连接c ++
【发布时间】:2011-10-22 12:35:08
【问题描述】:

现在我有一个 C++ 客户端应用程序,它使用 mysql.h 连接到 MYSQL 数据库,并且必须执行一些逻辑以防断开连接。我想知道这是否是在我的客户端断开连接的情况下重新连接到 MYSQL 数据库的最佳方式。

bool MYSQL::Reconnect(const char *host, const char *user, const char *passwd, const char *db)
{
bool out = false;

pid_t command_pid = fork();
if (command_pid == 0)
{
    while(1)
    {
        sleep(1);
        if (mysql_real_connect(&m_mysql, host, user, passwd, db, 0, NULL, 0) == NULL )
        {
            fprintf(stderr, "Failed to connect to database: Error: %s\n",
            mysql_error(&m_mysql));
        }
        else
        {
            m_connected = true;
            out = true;
            break;
        }
    }
    exit(0);
}

if (command_pid < 0)
    fprintf(stderr, "Could not fork process[reconnect]: %s\n", mysql_error(&m_mysql));

return out;
}

现在我接受了所有参数并进行了分叉。子进程每秒都尝试使用 sleep() 语句重新连接。这是一个好方法吗?谢谢

【问题讨论】:

    标签: c++ mysql database reconnect


    【解决方案1】:

    当然,完全没问题。您可能想考虑用类似

    的东西替换 while ( 1 ) 循环
      while ( NULL == mysql_real_connect( ... )) {
        sleep( 1 );
        ... 
      }
    

    这是一种通过实践学习的习语,但据我所知,您的代码运行良好。不要忘记在while 循环内放置一个计数器。

    【讨论】:

    • 谢谢皮特。计数器是干什么用的?
    • @Kaiser Wilhelm -- 如果mysql_real_connect( ) never 返回成功,计数器会让你脱离循环。
    【解决方案2】:

    抱歉,Kaiser Wilhelm,您的代码并没有按照您的想法执行。

    本质上,您是在尝试将分叉视为线程,但事实并非如此。

    当你 fork 一个子进程时,父进程被完全克隆,包括文件和套接字描述符,这就是你的程序连接到 MySQL 数据库服务器的方式。也就是说,当您 fork 时,父节点和子节点都将拥有自己的与数据库服务器的 same 连接副本。我假设父级仅在看到连接断开时才调用此Reconnect() 方法,并停止使用其现已失效的MySQL 连接对象m_mysql 的副本。如果是这样,当您开始重新连接操作时,连接的父级副本与客户端的一样无用。

    事实是,反过来也不是这样:一旦孩子设法重新连接到数据库服务器,父母的连接对象仍然失效。孩子所做的任何事情都不会传播给父母。在分叉之后,这两个进程完全独立,除非它们可能会尝试访问它们最初共享的某些 I/O 资源。例如,如果您在连接建立时调用此Reconnect() 并继续使用父级中的连接,则子级尝试与同一连接上的数据库服务器通信会混淆mysqldlibmysqlclient,可能会导致数据损坏或崩溃。

    如上所述,解决此问题的一种方法是使用线程而不是分叉。但是,请注意 many problems 在 MySQL C API 中使用线程。

    如果可以选择,我宁愿使用异步 I/O 在应用程序的主线程中进行后台连接尝试,但 MySQL C API 不允许这样做。

    您似乎在尝试重新连接数据库服务器时避免阻塞您的主应用程序线程。无论如何,您都可以通过setting the connect timeout 到 1 秒来同步执行此操作,这在 MySQL 服务器与客户端位于同一台机器或同一 LAN 上时很好。如果你可以容忍你的主线程阻塞长达一秒钟以导致连接尝试失败——最坏的情况发生在服务器位于单独的机器上并且它在物理上断开连接或防火墙时——这可能是比线程更清洁的解决方案。如果服务器机器仍在运行且端口未设置防火墙,例如在重新启动且 TCP/IP 堆栈[仍然]启动时,连接尝试可能会更快失败。

    【讨论】:

    • 感谢 Warren,一旦我尝试在主进程和分叉之间共享变量(这显然没有用),我很快就意识到了这一点。然而,即使这种方法不受欢迎,它在重新连接到数据库时确实有效。我做了一些测试,在最初连接失败后,我可以使用这种方法重新连接并轻松插入数据库。这是因为我使用的是m_mysql的地址吗?将来我可能会在同一个过程中执行此重新连接,但我只是好奇为什么会这样。
    • 当孩子设法重新连接时,它所做的只是退出,断开连接。父级仍然保持死连接,除非幸运的是使用了相同的文件或套接字描述符。一旦您开始将其他文件或套接字添加到程序中,此方法就会失败。另一种可能性是您在该连接上使用了 MySQL 重新连接选项,因此子节点所做的只是轮询服务器以告知父节点何时成功重新连接。这不是我对你的做法皱眉,而是我告诉你它已经坏了。
    【解决方案3】:

    据我所知,这并没有达到您的预期。

    逻辑问题

    Reconnect 根本不会“执行一些逻辑以防断开连接”。

    它会一遍又一遍地尝试连接,直到成功,然后停止。而已。永远不会再次检查连接的状态。如果连接断开,这段代码对它一无所知

    技术问题

    还要密切关注 Warren 提出的技术问题。

    【讨论】:

      猜你喜欢
      • 2014-03-18
      • 1970-01-01
      • 2020-09-21
      • 1970-01-01
      • 2019-03-27
      • 2016-05-12
      • 1970-01-01
      • 1970-01-01
      • 2014-04-25
      相关资源
      最近更新 更多