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數據引擎進行大數據量插入時,代碼中必須對該問題進行優化。