首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

C++ 實現 MySQL SOURCE 導入 SQL 腳本的封裝類

     編輯:MySQL 綜合教學

C++ 實現 MySQL SOURCE 導入 SQL 腳本的封裝類

需在無 MySQL 客戶端環境下程式化導入 SQL 腳本,MySQL C API 無直接 SOURCE 命令對應函數,需自行解析腳本文件逐條執行。本文提供完整的跨平台(Windows/Linux)C++ 封裝實現。

核心思路

  1. 按行讀取 .sql 文件。
  2. 以分號 ; 作為語句結束標識(簡易解析,不處理分號在字符串/註釋內的情況)。
  3. 累積單條 SQL,調用 mysql_real_query() 執行。

代碼結構

common.h - 基礎類型與宏

#ifndef _COMMON_H
#define _COMMON_H
#ifdef WIN32
#include 
typedef __int8 int8_t;  typedef __int16 int16_t;  typedef __int32 int32_t;  typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;  typedef unsigned __int16 uint16_t;  typedef unsigned __int32 uint32_t;  typedef unsigned __int64 uint64_t;
#define atoll(_String) _atoi64(_String)
#define PATH_DELIMTER "\\"
#else
#include   #include   #include   #include 
#define PATH_DELIMTER "/"
#endif
#include   #include   #include   #include   #include   #include   #include 
using namespace std;
enum SERVER_ACTION { SERVER_STARTNEW = 0 };
#endif

dbmanager.h - 介面定義

#ifndef _DBMANAGER_H
#define _DBMANAGER_H
#include 
using namespace std;
#include "common.h"
#include 

struct DBInfo { string host, user, passwd, db; uint16_t port; };

class DBManager {
public:
    DBManager(); ~DBManager();
    bool ConnectDB(DBInfo &dbInfo);
    bool SelectDB(string dbName);
    MYSQL_RES* ExeSql(const char *sql, int len);
    bool SourceSql(string fileName);  // 核心:導入腳本
private:
    MYSQL* mysqlInit(DBInfo &info);
    void mysqlClose();
    bool ReadSqlFile(string fileName, vector &sqlVec); // 解析文件
    MYSQL *m_mysqlConn;
    DBInfo m_dbConfig;
};
extern DBManager g_DBManager;
#endif

dbmanager.cpp - 實現


#include "dbmanager.h"
#include 

DBManager g_DBManager;

DBManager::DBManager() {}
DBManager::~DBManager() {}

bool DBManager::ConnectDB(DBInfo &dbInfo) {
    m_dbConfig = dbInfo;
    m_mysqlConn = mysqlInit(dbInfo);
    return m_mysqlConn != NULL;
}

MYSQL* DBManager::mysqlInit(DBInfo &info) {
    MYSQL *mysql = mysql_init(NULL);
    if (!mysql) return NULL;
    if (!mysql_real_connect(mysql, info.host.c_str(), info.user.c_str(),
                            info.passwd.c_str(), info.db.c_str(), info.port, NULL, 0)) {
        mysql_close(mysql); return NULL;
    }
#if MYSQL_VERSION_ID >= 50013
    my_bool reconnect = 1;
    mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
#else
    mysql->reconnect = 1;
#endif
    return mysql;
}

void DBManager::mysqlClose() {
    if (m_mysqlConn) { mysql_close(m_mysqlConn); m_mysqlConn = NULL; }
}

MYSQL_RES* DBManager::ExeSql(const char *sql, int len) {
    MYSQL_RES* res = NULL;
    int ret = mysql_real_query(m_mysqlConn, sql, len);
    if (ret == 0) res = mysql_store_result(m_mysqlConn);
    else printf("mysql query %s return errorcode:%d\n", sql, mysql_errno(m_mysqlConn));
    return res;
}

bool DBManager::SelectDB(string dbName) {
    return mysql_select_db(m_mysqlConn, dbName.c_str()) == 0;
}

bool DBManager::ReadSqlFile(string fileName, vector &sqlVec) {
    ifstream in(fileName.c_str(), ios::in);
    if (!in) return false;
    string line, singleSql;
    while (getline(in, line)) {
        singleSql += line;
        size_t pos = line.find(';');
        if (pos != string::npos) { // 遇到分號視為一條語句結束
            sqlVec.push_back(singleSql);
            singleSql.clear();
        }
    }
    in.close();
    return true;
}

bool DBManager::SourceSql(string fileName) {
    vector vecSql;
    if (!ReadSqlFile(fileName, vecSql)) { printf("導入 %s 失敗\n", fileName.c_str()); return false; }
    for (auto &s : vecSql) {
        ExeSql(s.c_str(), s.length());
    }
    return true;
}

使用示例

DBInfo info = {"localhost", "root", "root", "mydb", 3306};
g_DBManager.ConnectDB(info);
g_DBManager.SourceSql("init_schema.sql");

局限與改進方向

  • 簡易分號分割無法處理:存儲過程/觸發器內部的分號、字符串字面量中的分號、多行註釋。
  • 改進:引入完整 SQL 詞法分析器(如 libsqlparser)或按 MySQL 官方 mysql 客戶端源碼邏輯實現狀態機解析。
  • 異步/批量執行、事務控制、錯誤回滾機制可根據業務擴展。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved