65.9K
CodeProject 正在变化。 阅读更多。
Home

另一种使用 C++ 导入和导出 MySQL 数据库的方法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.44/5 (4投票s)

2015年3月31日

CPOL

5分钟阅读

viewsIcon

14541

downloadIcon

358

本文将介绍如何在不使用批处理文件的情况下将数据库导入 MySQL 服务器以及如何从 MySQL 服务器导出数据库。

引言

首先,我要感谢 Imagiro 先生对我上一篇文章的宝贵评论。他的评论促使我研究如何在不使用批处理文件的情况下导入和导出 MySQL 服务器数据库。在本文中,我试图开发一种支持“Unicode”和“MBCS”字符集的数据库导入和导出功能。本文展示了如何在不连接 MySQL 服务器甚至不使用 MySQL C API 的情况下将数据库导入/导出到/从 MySQL 服务器。

背景

这是一篇关于 MySQL 服务器导入和导出数据库的 C 语言编程教程。它涵盖了在不使用 MySQL 提供的 C API 的情况下导入和导出 MySQL。

MySQL 是领先的开源数据库管理系统。它是一个多用户、多线程的数据库管理系统。MySQL 的开发始于 1994 年,由瑞典公司 MySQL AB 完成。Sun Microsystems 于 2008 年收购了 MySQL AB。Sun 于 2010 年被 Oracle 收购。因此,如今 Oracle 公司是 MySQL 数据库的所有者。MySQL 是用 C/C++ 开发的。除了 C/C++,还有适用于 PHP、Python、Java、C#、Eiffel、Ruby、Tcl 和 Perl 的 API。

必备组件

  1. 安装 Visual Studio 2013(因为本文的代码是在 Visual Studio 2013 中开发的)
  2. 在本地计算机上安装 MySQL 服务器

设置

在深入编写数据库代码之前,我们需要按照以下设置配置我们的 Visual Studio 以使用 MySQL:

  1. 首先,将“libmysql.dll”从 MySQL 安装的位置复制出来,在我的电脑上,它位于“C:\Program Files\MySQL\MySQL Server 5.6\lib”。然后将其粘贴到您的应用程序的 exe/dll 将被创建的位置。
  2. 现在是时候配置 Visual Studio 以使用 MySQL C API 了:为此,请访问您项目的项目属性并相应地更新以下设置。
    1. C/C++ -> 常规 -> 其他包含目录 - C:\Program Files\MySQL\MySQL Server 5.6\include
    2. 链接器 -> 常规 -> 其他库目录 - C:\Program Files\MySQL\MySQL Server 5.6\include
    3. 链接器 -> 输入 -> 其他依赖项 - "C:\Program Files\MySQL\MySQL Server 5.6\lib\libmysql.lib"

注意:请根据您安装 MySQL 服务器的 PC 设置进行必要的更改。

使用代码

我创建了一个单独的类 (CDatabaseManipulation),它仅处理将数据库导入 MySQL 服务器和从 MySQL 服务器导出数据库。该类还包含到 MySQL 的连接,该连接仅用于从 MySQL 服务器检索数据库列表,从而简化了我们从 MySQL 服务器导出数据库的工作。有关详细信息,您需要查看本文随附的应用程序代码。因此,该类的用户可以自行决定他们是否对从 MySQL 服务器检索数据库列表感兴趣。

要在您的应用程序中使用此类,您首先需要按照“设置”部分中的说明更新您的 Visual Studio 设置。然后,您需要在要使用该类功能的代码位置包含“DatabaseManipulation.h”文件。然后创建该类的对象并访问“CDatabaseManipulation”类提供的功能。

将数据库导入 MySQL 服务器:要导入数据库,用户需要提供以下信息:

  1. 服务器主机名
  2. 用户名
  3. 密码
  4. 要导入的数据库名称
  5. 数据库导入文件(带有 .sql 扩展名)及其位置

在这里,我们可以通过以下 2 种方式完成导入数据库的任务:
        1) 使用 CreateProcess API
        2) 使用 ShellExecute API

由用户根据需要使用功能。

注意:有关 ImportDatabase 函数调用的信息,请参阅本文随附的应用程序代码中的类。

bool CDatabaseManipulation::ImportDatabase(/*[IN]*/const TCHAR *ptchHost,
                                           /*[IN]*/const TCHAR *ptchUserID, 
                                           /*[IN]*/const TCHAR *ptchPassword, 
                                           /*[IN]*/const TCHAR *ptchDatabaseNameToImport, 
                                           /*[IN]*/const TCHAR *ptchImportDatabaseFileWithPath)
/* ===================================================================================================
NAME OF FUNCTION:   CDatabaseManipulation::ImportDatabase
CREDIT:             Satish Jagtap
PURPOSE:            This function is used to import MySQL database.
Special Note:       Here we can achieve our task of importing database using following 2 ways:
                    1) Using CreateProcess API
                    2) Using ShellExecute API
                    User of this class can modify this function according to his/her need.
                    Means user can remove other section            
PARAMETERS:         [IN]  1) const TCHAR *ptchHost: Server host name
                    [IN]  2) const TCHAR *ptchUserID: User of MySQL server.
                    [IN]  3) const TCHAR *ptchPassword: Password  of MySQL server.
                    [IN]  4) const TCHAR *ptchDatabaseNameToImport: Database to import.
                    [IN]  5) constTCHAR *ptchImportDatabaseFileWithPath: Database file to import.
RETURN VALUE:       Returns true on success.
CALLS TO:           1) SearchForFilePath
CALLED FROM:        None
Added date:         31 March, 2015
Updated date:
=====================================================================================================*/
{
    bool bImportDBSuccess                = false;
    TCHAR strProgramFilePath[MAX_PATH]    = { 0 };

    //Retreive program file path
    if(!SHGetSpecialFolderPath(0, strProgramFilePath, CSIDL_PROGRAM_FILES, FALSE)) 
    {
        LPTSTR lpstrError = new TCHAR[1024];

        _stprintf_s(lpstrError, 1024, _T("Unable to retrieve program file path (%d)\n"), 
                                      GetLastError());
        m_objLogger.log(lpstrError);

        delete[] lpstrError;

        bImportDBSuccess = false;
    }
    else
    {
        TCHAR *strReturnSQLFilePath = new TCHAR[MAX_PATH];
        TCHAR *strImportCommand = new TCHAR[MAX_PATH];

        _tcscpy_s(strReturnSQLFilePath, MAX_PATH, _T(""));
        SearchForFilePath(strProgramFilePath, _T("mysql.exe"), strReturnSQLFilePath);

        _tcscat_s(strReturnSQLFilePath, MAX_PATH, _T("\\mysql.exe"));

        //Populate command to import database
        _tcscpy_s(strImportCommand, MAX_PATH, _T("-u"));
        _tcscat_s(strImportCommand, MAX_PATH, ptchUserID);
        _tcscat_s(strImportCommand, MAX_PATH, _T(" -p"));
        _tcscat_s(strImportCommand, MAX_PATH, ptchPassword);
        _tcscat_s(strImportCommand, MAX_PATH, _T(" -h "));
        _tcscat_s(strImportCommand, MAX_PATH, ptchHost);
        _tcscat_s(strImportCommand, MAX_PATH, _T(" -e "));
        _tcscat_s(strImportCommand, MAX_PATH, _T(" \"drop database if exists "));
        _tcscat_s(strImportCommand, MAX_PATH, ptchDatabaseNameToImport);
        _tcscat_s(strImportCommand, MAX_PATH, _T("; "));
        _tcscat_s(strImportCommand, MAX_PATH, _T(" create database "));
        _tcscat_s(strImportCommand, MAX_PATH, ptchDatabaseNameToImport);
        _tcscat_s(strImportCommand, MAX_PATH, _T("; "));
        _tcscat_s(strImportCommand, MAX_PATH, _T("use "));
        _tcscat_s(strImportCommand, MAX_PATH, ptchDatabaseNameToImport);
        _tcscat_s(strImportCommand, MAX_PATH, _T(";\\. "));
        _tcscat_s(strImportCommand, MAX_PATH, ptchImportDatabaseFileWithPath);
        _tcscat_s(strImportCommand, MAX_PATH, _T("\""));

        /***************************************************************************************
        Here we can achieve our task of importing database using following 2 ways:
        1) Using CreateProcess API
        2) Using ShellExecute API
        Note: I have just commented "Achieve import database process using CreateProcess API"
              section
        ***************************************************************************************/
    #pragma region "Achieve import database process using CreateProcess API"
        //LPTSTR strImportDatabaseCommandLine = new TCHAR[1024];

        //_stprintf_s(strImportDatabaseCommandLine, 1024, _T("%s %s"), strReturnSQLFilePath, 
        //                                                             strImportCommand);

        //STARTUPINFO si = { 0 }; // alternative way to zero array
        //si.cb = sizeof(si);
        //PROCESS_INFORMATION pi = { 0 };

        //if (!CreateProcess(NULL,
        //                    strImportDatabaseCommandLine,
        //                    NULL,
        //                    NULL,
        //                    FALSE,
        //                    0,
        //                    NULL,
        //                    NULL,
        //                    &si,
        //                    &pi)
        //  )
        //{
        //    LPTSTR lpstrError = new TCHAR[1024];

        //    _stprintf_s(lpstrError, 1024, _T("CreateProcess failed (%d)\n"), GetLastError());
        //    m_objLogger.log(lpstrError);

        //    delete[] lpstrError;

        //    bImportDBSuccess = false;
        //}
        //else
        //{
        //    bImportDBSuccess = true;
        //}

        //WaitForSingleObject(pi.hProcess, INFINITE);
        //CloseHandle(pi.hProcess);
        //CloseHandle(pi.hThread);

        //delete [] strImportDatabaseCommandLine;
        //strImportDatabaseCommandLine = NULL;
    #pragma endregion

    #pragma region "Achieve import database process using ShellExecute API"
        UINT nReturnErrorCode = (UINT)ShellExecute(NULL, 
                                                    _T("open"),
                                                    strReturnSQLFilePath, //mysql.exe file path
                                                    strImportCommand, //command to import database 
                                                                      //into MySQL server
                                                    NULL, 
                                                    SW_HIDE); //hides command window

        if(nReturnErrorCode <= 32)
        {
            LPTSTR lpstrError = new TCHAR[1024];

            _stprintf_s(lpstrError, 1024, _T("ShellExecute failed (%d)\n"), GetLastError());
            m_objLogger.log(lpstrError);

            delete[] lpstrError;

            bImportDBSuccess = false;
        }
        else
        {
            bImportDBSuccess = true;
        }
    #pragma endregion

        delete [] strReturnSQLFilePath;
        strReturnSQLFilePath = NULL;
        delete [] strImportCommand;
        strImportCommand = NULL;
    }

    return bImportDBSuccess;
}

检索当前正在运行的 MySQL 服务器中的数据库列表:要从 MySQL 服务器导出数据库,我们需要知道当前正在运行的 MySQL 服务器中可用的数据库。本节从 MySQL 服务器检索数据库列表。这里我创建了此函数的两个版本:一个与 Unicode 字符集一起使用,另一个与 MBCS 一起使用。

#pragma region Retrieve databases list from currently running MySqlServer

#ifdef UNICODE

void CDatabaseManipulation::RetrieveDatabasesListInMySqlServer(vector<wchar_t*> &vecMySqlDatabasesList)
/* ===================================================================================================
NAME OF FUNCTION:   CDatabaseManipulation::RetrieveDatabasesListInMySqlServer
CREDIT:             Satish Jagtap
PURPOSE:            This function is used to receives databases list in currently running MySql 
                    server instance
PARAMETERS:         1) vector<wchar_t*> &vecMySqlDatabasesList - Receives databases list in currently 
                                                                 running MySql server instance
RETURN VALUE:       None
CALLS TO:           None
CALLED FROM:        None
Added date:         27 March, 2015
Updated date:
====================================================================================================*/
{
    char strTemp[MAX_PATH]        = { 0 };
    size_t nTempLen                = 0;
    
    wcstombs_s(&nTempLen, strTemp, _T("%"), wcslen(_T("%")) + 1);
    MYSQL_RES *myqlResult = mysql_list_dbs(mysqlConnection, strTemp /* fetch all */);
    
    if (!myqlResult) 
    {
        LPTSTR lptstrError = new TCHAR[1024];

        _stprintf_s(lptstrError, 1024, _T("Couldn't get db list: %s"), GetError());
        m_objLogger.log(lptstrError);

        delete [] lptstrError;
    }
    else 
    {
        MYSQL_ROW mysqlRow;
        
        while(mysqlRow = mysql_fetch_row(myqlResult)) 
        {
            size_t nLen                    = 0;
            int nLenInfoSchema            = strlen(mysqlRow[0]) + 1;
            wchar_t wcstrRow[MAX_PATH]    = { 0 };

            mbstowcs_s(&nLen, wcstrRow, mysqlRow[0], nLenInfoSchema);

            if((_tcscmp(wcstrRow, _T("information_schema"))) && 
               (_tcscmp(wcstrRow, _T("performance_schema"))) && 
               (_tcscmp(wcstrRow, _T("mysql"))))
            {
                size_t nTempLen                = 0;
                wchar_t strRow[MAX_PATH]    = { 0 };

                strMySQLResultRow = new wchar_t[MAX_PATH];

                mbstowcs_s(&nTempLen, strRow, mysqlRow[0], strlen(mysqlRow[0]) + 1);
                _tcscpy_s(strMySQLResultRow, _tcslen(strRow) + 1, strRow);

                vecMySqlDatabasesList.push_back(strMySQLResultRow);
            }
        }
    }
}
#else
void CDatabaseManipulation::RetrieveDatabasesListInMySqlServer(vector<CHAR*> &vecMySqlDatabasesList)
/* ===================================================================================================
NAME OF FUNCTION:   CDatabaseManipulation::RetrieveDatabasesListInMySqlServer
CREDIT:             Satish Jagtap
PURPOSE:            This function is used to receives databases list in currently running MySql 
                    server instance
PARAMETERS:         1) vector<CHAR*> &vecMySqlDatabasesList - Receives databases list in currently 
                                                              running MySql server instance
RETURN VALUE:       None
CALLS TO:           None
CALLED FROM:        None
Added date:         21 March, 2015
Updated date:
=====================================================================================================*/
{
    MYSQL_RES *myqlResult = mysql_list_dbs(mysqlConnection, _T("%") /* fetch all */);

    if (!myqlResult) 
    {
        LPTSTR lptstrError = new TCHAR[1024];

        _stprintf_s(lptstrError, 1024, _T("Couldn't get db list: %s"), GetError());
        m_objLogger.log(lptstrError);

        delete [] lptstrError;
    }
    else 
    {
        MYSQL_ROW mysqlRow;

        while(mysqlRow = mysql_fetch_row(myqlResult)) 
        {
            if((_tcscmp(mysqlRow[0], _T("information_schema"))) && (_tcscmp(mysqlRow[0], _T("performance_schema"))) && (_tcscmp(mysqlRow[0], _T("mysql"))))
            {
                vecMySqlDatabasesList.push_back(mysqlRow[0]);
            }
        }
    }
}
#endif
#pragma endregion

将数据库导出到 MySQL 服务器:要导出数据库,用户需要提供以下信息:

  1. 用户名
  2. 密码
  3. 要导出的数据库名称
  4. 数据库导出文件(带有 .sql 扩展名)及其位置

在这里,我们可以通过以下 2 种方式完成导出数据库的任务:
        1) 使用 CreateProcess API
        2) 使用 ShellExecute API

由用户根据需要使用功能。

注意:有关 ExportDatabase 函数调用的信息,请参阅本文随附的应用程序代码中的类。

bool CDatabaseManipulation::ExportDatabase(/*[IN]*/const TCHAR *ptchUserID, 
                                           /*[IN]*/const TCHAR *ptchPassword, 
                                           /*[IN]*/const TCHAR *ptchDatabaseNameToExport, 
                                           /*[IN]*/const TCHAR *ptchExportDatabaseFileWithPath)
/* ===================================================================================================
NAME OF FUNCTION:   CDatabaseManipulation::ExportDatabase
CREDIT:             Satish Jagtap
PURPOSE:            This function is used to export MySQL database.
Special Note:       Here we can achieve our task of exporting database using following 2 ways:
                    1) Using CreateProcess API
                    2) Using ShellExecute API
                    User of this class can modify this function according to his/her need.
                    Means user can remove other section    
PARAMETERS:         [IN]  1) const TCHAR *ptchUserID: User of MySQL server.
                    [IN]  2) const TCHAR *ptchPassword: Password  of MySQL server.
                    [IN]  3) const TCHAR *ptchDatabaseNameToExport: Database to export.
                    [IN]  4) constTCHAR *ptchExportDatabaseFileWithPath: Database file to export.
RETURN VALUE:       Returns true on success.
CALLS TO:           1) SearchForFilePath
CALLED FROM:        None
Added date:         31 March, 2015
Updated date:
====================================================================================================*/
{
    bool bExportDBSuccess                = false;
    TCHAR strProgramFilePath[MAX_PATH]    = { 0 };

    //Retreive program file path
    if(!SHGetSpecialFolderPath(0, strProgramFilePath, CSIDL_PROGRAM_FILES, FALSE)) 
    {
        LPTSTR lpstrError = new TCHAR[1024];

        _stprintf_s(lpstrError, 1024, _T("CreateProcess failed (%d)\n"), GetLastError());
        m_objLogger.log(lpstrError);

        delete[] lpstrError;

        bExportDBSuccess = false;
    }
    else
    {
        TCHAR *strReturnSQLFilePath = new TCHAR[MAX_PATH];
        TCHAR *strExportCommand        = new TCHAR[MAX_PATH];

        _tcscpy_s(strReturnSQLFilePath, MAX_PATH, _T(""));
        SearchForFilePath(strProgramFilePath, _T("mysqldump.exe"), strReturnSQLFilePath);
        _tcscat_s(strReturnSQLFilePath, MAX_PATH, _T("\\mysqldump.exe"));

        //Populate command to export database
        _tcscpy_s(strExportCommand, MAX_PATH, _T(" --user="));
        _tcscat_s(strExportCommand, MAX_PATH, ptchUserID);
        _tcscat_s(strExportCommand, MAX_PATH, _T(" --password="));
        _tcscat_s(strExportCommand, MAX_PATH, ptchPassword);
        _tcscat_s(strExportCommand, MAX_PATH, _T(" "));
        _tcscat_s(strExportCommand, MAX_PATH, ptchDatabaseNameToExport);
        _tcscat_s(strExportCommand, MAX_PATH, _T(" -r "));
        _tcscat_s(strExportCommand, MAX_PATH, ptchExportDatabaseFileWithPath);

        /***************************************************************************************
        Here we can achieve our task of exporting database using following 2 ways:
        1) Using CreateProcess API
        2) Using ShellExecute API
        Note: I have just commented "Achieve export database process using CreateProcess API"
              section
        ***************************************************************************************/
    #pragma region "Achieve export database process using CreateProcess API"
        //LPTSTR strExportDatabaseCommandLine = new TCHAR[1024];

        //_stprintf_s(strExportDatabaseCommandLine, 1024, _T("%s %s"), strReturnSQLFilePath, 
        //                                                             strExportCommand);

        //STARTUPINFO si = { 0 }; // alternative way to zero array
        //si.cb = sizeof(si);
        //PROCESS_INFORMATION pi = { 0 };

        //if (!CreateProcess(NULL,
        //                    strExportDatabaseCommandLine,
        //                    NULL,
        //                    NULL,
        //                    FALSE,
        //                    0,
        //                    NULL,
        //                    NULL,
        //                    &si,
        //                    &pi)
        //  )
        //{
        //    LPTSTR lpstrError = new TCHAR[1024];

        //    _stprintf_s(lpstrError, 1024, _T("CreateProcess failed (%d)\n"), GetLastError());
        //    m_objLogger.log(lpstrError);

        //    delete[] lpstrError;

        //    bExportDBSuccess = false;
        //}
        //else
        //{
        //    bExportDBSuccess = true;
        //}

        //WaitForSingleObject(pi.hProcess, INFINITE);
        //CloseHandle(pi.hProcess);
        //CloseHandle(pi.hThread);

        //delete [] strExportDatabaseCommandLine;
        //strExportDatabaseCommandLine = NULL;
    #pragma endregion

    #pragma region "Achieve export database process using ShellExecute API"
        UINT nReturnErrorCode = (UINT)ShellExecute(NULL, 
                                                    _T("open"), 
                                                    strReturnSQLFilePath, //mysqldump.exe file path
                                                    strExportCommand, //command to import 
                                                                      //database into MySQL server
                                                    _T(""), 
                                                    SW_HIDE); //hides command window

        if(nReturnErrorCode <= 32)
        {
            LPTSTR lpstrError = new TCHAR[1024];

            _stprintf_s(lpstrError, 1024, _T("ShellExecute failed (%d)\n"), GetLastError());
            m_objLogger.log(lpstrError);

            delete[] lpstrError;

            bExportDBSuccess = false;
        }
        else
        {
            bExportDBSuccess = true;
        }
    #pragma endregion

        delete [] strReturnSQLFilePath;
        strReturnSQLFilePath = NULL;
        delete [] strExportCommand;
        strExportCommand = NULL;
    }

    return bExportDBSuccess;
}

本文随附的应用程序代码是使用 MFC 基于对话框的应用程序开发的完整源代码。本文中的应用程序代码与我上一篇文章有很大不同。这是应用程序窗口的样子:

使用应用程序的步骤

  1. 首先,在“输入 MySQL 服务器详细信息”部分输入所需信息。
  2. 使用“导入数据库”部分导入数据库。
  3. 要导出数据库,请先使用“检索数据库列表”按钮检索数据库列表。该应用程序附带一个可编辑的组合框(“选择数据库”),用户可以在其中手动输入他们想要导出的数据库名称,从而跳过“检索数据库列表”功能。然后,用户可以通过在“导出数据库”部分提供更多详细信息来导出数据库。

关注点

在我上一篇文章“使用 C++ 导入和导出 MySQL 数据库”中,我创建了用于导入和导出数据库的批处理文件。但在本文中,我跳过了那部分,提供了不同的功能来导入和导出数据库到/从 MySQL 服务器。我还创建了此源代码以同时支持 Unicode 字符集和多字节字符集。

备注

  1. 请记住更改您的项目设置,使其指向MySQL 包含文件和MySQL 库。
  2. 将“libmysql.dll”从 MySQL 安装的位置复制出来,在我的电脑上,它位于“C:\Program Files\MySQL\MySQL Server 5.6\lib”。然后将其粘贴到您的应用程序的 exe/dll 将被创建的位置。
© . All rights reserved.