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






4.44/5 (4投票s)
本文将介绍如何在不使用批处理文件的情况下将数据库导入 MySQL 服务器以及如何从 MySQL 服务器导出数据库。
- 下载 ImportExportMySQLDBWithoutUsingBatchFile.rar - 268 KB
- 下载 ImportExportMySQLDBWithoutUsingBatchFile.zip - 289.3 KB
引言
首先,我要感谢 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。
必备组件
- 安装 Visual Studio 2013(因为本文的代码是在 Visual Studio 2013 中开发的)
- 在本地计算机上安装 MySQL 服务器
设置
在深入编写数据库代码之前,我们需要按照以下设置配置我们的 Visual Studio 以使用 MySQL:
- 首先,将“libmysql.dll”从 MySQL 安装的位置复制出来,在我的电脑上,它位于“C:\Program Files\MySQL\MySQL Server 5.6\lib”。然后将其粘贴到您的应用程序的 exe/dll 将被创建的位置。
- 现在是时候配置 Visual Studio 以使用 MySQL C API 了:为此,请访问您项目的项目属性并相应地更新以下设置。
- C/C++ -> 常规 -> 其他包含目录 - C:\Program Files\MySQL\MySQL Server 5.6\include
- 链接器 -> 常规 -> 其他库目录 - C:\Program Files\MySQL\MySQL Server 5.6\include
- 链接器 -> 输入 -> 其他依赖项 - "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 服务器:要导入数据库,用户需要提供以下信息:
- 服务器主机名
- 用户名
- 密码
- 要导入的数据库名称
- 数据库导入文件(带有 .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 服务器:要导出数据库,用户需要提供以下信息:
- 用户名
- 密码
- 要导出的数据库名称
- 数据库导出文件(带有 .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 基于对话框的应用程序开发的完整源代码。本文中的应用程序代码与我上一篇文章有很大不同。这是应用程序窗口的样子:
使用应用程序的步骤
- 首先,在“输入 MySQL 服务器详细信息”部分输入所需信息。
- 使用“导入数据库”部分导入数据库。
- 要导出数据库,请先使用“检索数据库列表”按钮检索数据库列表。该应用程序附带一个可编辑的组合框(“选择数据库”),用户可以在其中手动输入他们想要导出的数据库名称,从而跳过“检索数据库列表”功能。然后,用户可以通过在“导出数据库”部分提供更多详细信息来导出数据库。
关注点
在我上一篇文章“使用 C++ 导入和导出 MySQL 数据库”中,我创建了用于导入和导出数据库的批处理文件。但在本文中,我跳过了那部分,提供了不同的功能来导入和导出数据库到/从 MySQL 服务器。我还创建了此源代码以同时支持 Unicode 字符集和多字节字符集。
备注
- 请记住更改您的项目设置,使其指向MySQL 包含文件和MySQL 库。
- 将“libmysql.dll”从 MySQL 安装的位置复制出来,在我的电脑上,它位于“C:\Program Files\MySQL\MySQL Server 5.6\lib”。然后将其粘贴到您的应用程序的 exe/dll 将被创建的位置。