使用C libmysqlclient的原因不明的MySQL行为

时间:2016-09-13 02:49:58

标签: mysql c key

我在C中编写了一个处理引擎,它从表中提取40k条记录,处理数据并将结果写入不同的表。当我将处理过的数据打印到屏幕上时,它看起来很完美,因此所有变量都保持正确的值。我需要将数据写入一个有3列作为主键的表。我像这样创建表:

CREATE TABLE halfcomp 
(
    MarketCode varchar(20) NOT NULL,
    TRZNum varchar(20) NOT NULL,
    origTRZNum varchar(20) NOT NULL,
    PRIMARY KEY (MarketCode, TRZNum, origTRZNum)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

当C程序写入数据库时​​,我得到的结果是垃圾。我得到重复的值,我不应该,结果是乱序,列看起来切换到位等等。我一直在玩这个几天,我认为它与主键有关。

我认为这是因为我使用自动递增的整数主键创建了另一个表,它将我的其他值释放为普通的旧表值。我创建了这样的表:

CREATE TABLE halfcomp
(
    Ind int(11) auto_increment NOT NULL,
    MarketCode varchar(20) DEFAULT NULL,
    TRZNum varchar(20) DEFAULT NULL,
    origTRZNum varchar(20) DEFAULT NULL,
    PRIMARY KEY (Ind)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

当我使用相同的C代码写入此表时,结果非常完美。没有重复值,没有混合列。但事情就是这样,我需要MarketCode,TRZNum和origTRZNum列作为主键。我不恰当地创建了我的第一张桌子吗?我很茫然。

我已经使用细齿梳在C程序上,它看起来正确,并且相同的C代码适用于其他表。但是使用这个表,它不起作用。任何见解都将非常感激!谢谢!

编辑:我已更新代码。我不再使用malloc任意或sprintf,我将缓冲区值直接设置为我的字符串变量的值。我也尝试在字符串末尾添加“\ 0”。到目前为止,没有任何帮助,我得到了同样的不稳定行为。仅当值为主键时才会发生这种情况,否则会正确加载。我必须假设C在开始时将数据库信息传递给我时在字符串末尾添加一个空终止符,并且我在处理数据时使用strcpy来回传递值,所以我必须相信null终止符已经存在。还有其他想法吗?

int writeDB(void) {
    MYSQL *conn2;
    MYSQL_STMT *stmt2;
    MYSQL_BIND bind2[3];

    char *server = "localhost";
    char *user = "root";
    char *password = "";
    char *database = "thekeydb";
    int port = 3306;

    int k;
    int length = 15000;
    unsigned long mc2_length, mn2_length, om2_length;
    const char *insertStmt2 = "INSERT INTO tempcomp (MarketCode, TRZNum, origTRZNum) VALUES (?,?,?)";

    conn2 = mysql_init(NULL);
    mysql_real_connect(conn2, server,user,password,database, port, NULL, 0);
    stmt2 = mysql_stmt_init(conn2);
    mysql_autocommit(conn2, 0);
    mysql_query(conn2, "START TRANSACTION");

    for (k=0; k < length; k++) {
        memset((void *) bind2, 0, sizeof(bind2));

        mc2_length = strlen(comps[k].marketCode);
        mn2_length = strlen(comps[k].trzNum);
        om2_length = strlen(comps[k].origTrzNum);

        if (mysql_stmt_prepare(stmt2, insertStmt2, strlen(insertStmt2)) != 0) {
            printf("Unable to create new session: Could not prepare statement\n");
        }

        bind2[0].buffer_type = MYSQL_TYPE_STRING;
        bind2[0].buffer = comps[k].marketCode;
        bind2[0].buffer_length = STRING_SIZE;
        bind2[0].is_null = 0;
        bind2[0].length = &mc2_length;

        bind2[1].buffer_type = MYSQL_TYPE_STRING;
        bind2[1].buffer = comps[k].trzNum;
        bind2[1].buffer_length = STRING_SIZE;
        bind2[1].is_null = 0;
        bind2[1].length = &mn2_length;

        bind2[2].buffer_type = MYSQL_TYPE_STRING;
        bind2[2].buffer = comps[k].origTrzNum;
        bind2[2].buffer_length = STRING_SIZE;
        bind2[2].is_null = 0;
        bind2[2].length = &om2_length;

        if (mysql_stmt_bind_param(stmt2, bind2) != 0) {
            printf("Unable to create new session: Could not bind parameters");
        }
        mysql_stmt_execute(stmt2);
        printf("%s, %s, %s, %s\n", comps[k].marketCode, comps[k].trzNum, comps[k].origTrzNum, comps[k].address);
    }

    mysql_query(conn2, "COMMIT");
    mysql_autocommit(conn2, 1);
    mysql_stmt_free_result(stmt2);
    mysql_stmt_close(stmt2);
    mysql_close(conn2);

    return 1;
}

2 个答案:

答案 0 :(得分:0)

几乎可以肯定,你不是val cx = new StringField("blockId", "CX") val seg = StringField("segmentation", "ABC") val ver = NumberField("version", "1.0") val myBlock = Block(cx, Seq(seg, ver)) 终止你的字符串。如果将字符串作为参数传递给 libmysqlclient 中的预准备语句,则必须指定字符串的长度。如果您的字符串未null终止并且您使用null将长度传递给strlen()结构,或者您 1 将它们传递给{{1}或者类似于构建查询,然后会出现类似于你的porgram行为的意外行为。

1 如果您真的这样做,请不要这样做,而是使用预备语句。

答案 1 :(得分:0)

为了社区,我必须诚实地回答这个问题,不过我承认我很尴尬。此时,我相信我一直在正确地将数据写入数据库,但是错误地查看数据库数据以进行比较。当我将数据打印到屏幕上时,我正在查看三列。第一个是完全重复的市场代码,第二个是相当随机的代码,第三个代码是以5或8组或其他方式重复的代码。当我做一个“SELECT * FROM tempcomp”来查看数据时,它是第二列会重复,但是在较小的组中,如2或3,第三列看起来是随机的。我现在相信MySQL Workbench在将数据呈现给我之前就以某种方式对数据进行排序。因此,数据库显示与程序显示的不同。当我使用auto_incrementing整数作为主键时,数据库以与屏幕显示相同的顺序显示数据。但是当我的三列是主键时,它对输出进行了不同的排序。尝试解决这个问题已经过了3天,并且发现我的代码实际上没有任何错误,至少可以说是尴尬。