C API向MySQL插入批量數據的快速方法——關於mysql_autocommit


  MySQL默認的數據提交操作模式是自動提交模式(autocommit)。這就表示除非顯式地開始一個事務,否則每個查詢都被當做一個單獨的事務自動執行。我們可以通過設置autocommit的值改變是否是自動提交autocommit模式。查詢當前數據庫事務提交方式的命令為:

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.04 sec)

其中“ON”代表autocommit模式為打開狀態,使用MySQL C API關閉事務自動提交的代碼為:

        MYSQL mysql;
        mysql_init(&mysql);
        if(!mysql_real_connect(&mysql, host, user, password, schema, port, NULL, 0)) 
        {
            printf("MySQL數據庫連接失敗。\n");
            return -1;
        }
        int set_cs_r = mysql_set_character_set(&mysql, "gbk");
        mysql_autocommit(&mysql, 0);

  MySQL默認的存儲引擎是MyISAM,MyISAM存儲引擎不支持事務處理,所以改變autocommit沒有什么作用,InnoDB存儲引擎支持事務處理。InnoDB表引擎下關閉mysql自動事務提交可以大大提高數據插入的效率,這是因為如果需要插入1000條數據,mysql會自動發起(提交)1000次的數據寫入請求,如果把autocommit關閉掉,通過程序來控制,只要一次commit就可以搞定。示例代碼(邏輯過程)如下:

int H_Utility::insertRecordsToMySQL(
    const char* dataFilePath,
    const char* host,
    const char* user,
    const char* password,
    const char* schema,
    const char* table,
    const int    port,
    const char* logFilePath)
{
    ifstream rpf;
    rpf.open(dataFilePath);
    int lineCount = 0;
    if (rpf.is_open())
    {
        MYSQL mysql;
        mysql_init(&mysql);
        if(!mysql_real_connect(&mysql, host, user, password, schema, port, NULL, 0)) 
        {
            printf("MySQL數據庫連接失敗。\n");
            return -1;
        }
        ofstream f1(logFilePath);
        if (!f1.is_open())
        {
            printf("日志文件創建失敗!\n");
            return 0;
        }
        mysql_autocommit(&mysql, 0);//關閉自動提交
        char* out_text = new char[1024];
        int cursor = 0;
        while (!rpf.eof())
        {
            memset(out_text,0x00,1024);
            rpf.getline(out_text,1024);
            string str(out_text);
            if (str.length()>0)
            {
                lineCount++;
                if (lineCount>1)
                {
                    std::vector<string> strVec;
                    int cellCount = H_Utility::stringSplitToVector(str.c_str(), strVec, ",");
                    if (cellCount<3)
                    {
                        printf("第%d行數據不完整,寫入失敗:\n",lineCount);
                        f1<<str<<endl;
                        continue;
                    }
                    string sql_str = "";
                    sql_str.append("INSERT INTO `").append(SCHEMA_NAME).append("`.`").append(TABLE_NAME).append("` ");
                    sql_str.append("(id,name,birthday) values (");
                    sql_str.append(strVec[0]).append(",'").append(strVec[1]).append("',");
                    sql_str.append("STR_TO_DATE('").append(strVec[31]).append("','%Y-%m-%d %H:%i:%s'))");
                    int iSuccess = mysql_query(&mysql, sql_str.c_str()); 
                    if (iSuccess != 0)
                    {
                        const char *mysql_err = mysql_error(&mysql);
                        printf("%s\n",mysql_err);
                        f1<<str<<endl;
                    }
                    else
                    {
                        cursor++;
                    }
                    if (cursor==50000)//每50000條記錄提交一次
                    {
                        mysql_commit(&mysql);
                        cursor = 0;
                        printf("%d\n",lineCount);
                    }
                }
            }
        }
        delete []out_text;
        rpf.close();
        f1.flush();
        f1.close();
        mysql_close(&mysql);
    }
    return lineCount;
}

  在本人筆記本電腦上(Thinkpad T430; i5-3380 CPU; 4G DDR3 RAM; 500G&7200RPM HDD; Win7 旗艦版 x64; MySQL 5.6 社區版)的測試結果為:上述代碼往mysql中插入200萬條記錄(數據文件大小約為300M)耗時僅約為345秒,而逐條提交時運行約3小時僅僅寫入了不到50萬條數據,由此可見在使用InnoDB數據引擎進行大數據量插入時,代碼中必須對該問題進行優化。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM