zoukankan      html  css  js  c++  java
  • 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数据库连接失败。
    ");
                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数据库连接失败。
    ");
                return -1;
            }
            ofstream f1(logFilePath);
            if (!f1.is_open())
            {
                printf("日志文件创建失败!
    ");
                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行数据不完整,写入失败:
    ",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
    ",mysql_err);
                            f1<<str<<endl;
                        }
                        else
                        {
                            cursor++;
                        }
                        if (cursor==50000)//每50000条记录提交一次
                        {
                            mysql_commit(&mysql);
                            cursor = 0;
                            printf("%d
    ",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数据引擎进行大数据量插入时,代码中必须对该问题进行优化。

  • 相关阅读:
    并发队列、线程池、锁
    JVM、垃圾收集器
    Socket网络编程
    Netty入门
    SpringCloud微服务负载均衡与网关
    Android监听耳机按键事件
    利用本地不同磁盘文件夹作为git远程仓库进行灾备
    chrome浏览器form中button每点击一次,form就会提交一次
    [企业路由器] 一对一NAT映射设置指导
    win7镜像自带IE9的卸载
  • 原文地址:https://www.cnblogs.com/lchb/p/4520382.html
Copyright © 2011-2022 走看看