sqlite3_prepare_v2/sqlite3_exec

Dev*_*000 12 sqlite objective-c ios

关于sqlite3的几个问题:

1.何时需要使用第一种方法而另一种方式?它们之间有区别吗?

sqlite3_prepare_v2(_contactDB, sql_stmt_getIdRecepteur, -1, &sqlStatement, NULL);
Run Code Online (Sandbox Code Playgroud)

if(sqlite3_prepare_v2(_contactDB, sql_stmt_getIdRecepteur, -1, &sqlStatement, NULL) == SQLITE_OK) {}
Run Code Online (Sandbox Code Playgroud)

2.什么时候最多指示使用'sqlite3_exec'而不是'sqlite3_prepare_v2'?

3.何时需要使用第一个,第二个或第三个:

while(sqlite3_step(sqlStatement) == SQLITE_ROW){}
if(sqlite3_step(sqlStatement) == SQLITE_ROW){}
if(sqlite3_step(sqlStatement) == SQLITE_DONE){}
Run Code Online (Sandbox Code Playgroud)

先感谢您

Rob*_*Rob 16

  1. 应始终检查SQLite函数的返回值,以确保它成功,因此最if优选使用该语句.如果失败,可以调用sqlite3_errmsg()检索错误的C字符串描述.

  2. 在任何情况下都可以使用sqlite3_prepare_v2(而不是sqlite3_exec):

    • 一个是返回数据,因此将调用sqlite3_step后跟一个或多个sqlite3_column_xxx函数,为每行数据重复该过程; 要么

    • 一个是将值绑定到?SQL中的占位符sqlite3_bind_xxx.

    可以从上面推断出sqlite3_exec只有在(a)SQL字符串没有参数时才会使用; (b)SQL不返回任何数据.这sqlite3_exec更简单,但只应在这些特殊情况下使用.

    请注意:关于?占位符的这一点非常重要:应该避免手动构建SQL语句(例如,使用stringWithFormat或Swift字符串插值),尤其是在插入的值包括最终用户输入时.例如,如果使用用户输入调用sqlite3_execwith INSERT,UPDATE或者DELETE使用用户输入创建的语句(例如,将用户提供的某些值插入数据库中),则可能会出现因未转义的引号和转义符号等引起的问题.一个也暴露于SQL注入攻击.

    例如,如果commentString由于用户输入而提供,则这是不可取的:

    NSString *sql = [NSString stringWithFormat:@"INSERT INTO COMMENTS (COMMENT) VALUES ('%@')", commentString];
    if (sqlite3_exec(database, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
        NSLog(@"Insert failure: %s", sqlite3_errmsg(database));
    }
    
    Run Code Online (Sandbox Code Playgroud)

    相反,你应该:

    const char *sql = "INSERT INTO COMMENTS (COMMENT) VALUES (?)";
    if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK) {
        NSLog(@"Prepare failure: %s", sqlite3_errmsg(database));
        return;
    }
    if (sqlite3_bind_text(statement, 1, [commentString UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
        NSLog(@"Bind 1 failure: %s", sqlite3_errmsg(database));
        sqlite3_finalize(statement);
        return;
    }
    if (sqlite3_step(statement) != SQLITE_DONE) {
        NSLog(@"Step failure: %s", sqlite3_errmsg(database));
    }
    sqlite3_finalize(statement);
    
    Run Code Online (Sandbox Code Playgroud)

    注意,如果这个正确的实现感觉太多工作,你可以使用FMDB库,这将简化它:

    if (![db executeUpdate:@"INSERT INTO COMMENTS (COMMENT) VALUES (?)", commentString]) {
        NSLog(@"Insert failure: %@", [db lastErrorMessage]);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这提供了严格的sqlite3_prepare_v2方法,但sqlite3_exec界面简单.

  3. 检索多行数据时,可以使用:

    while(sqlite3_step(sqlStatement) == SQLITE_ROW) { ... }
    
    Run Code Online (Sandbox Code Playgroud)

    或者,更好的是,如果你想做正确的错误处理,你会做:

    int rc;
    while ((rc = sqlite3_step(sqlStatement)) == SQLITE_ROW) {
        // process row here
    }
    if (rc != SQLITE_DONE) {
         NSLog(@"Step failure: %s", sqlite3_errmsg(database));
    }
    
    Run Code Online (Sandbox Code Playgroud)

    检索单行数据时,可以:

    if (sqlite3_step(sqlStatement) != SQLITE_ROW) {
        NSLog(@"Step failure: %s", sqlite3_errmsg(database));
    }
    
    Run Code Online (Sandbox Code Playgroud)

    执行不会返回任何数据的SQL时,会:

    if (sqlite3_step(sqlStatement) != SQLITE_DONE) {
        NSLog(@"Step failure: %s", sqlite3_errmsg(database));
    }
    
    Run Code Online (Sandbox Code Playgroud)

使用SQLite C界面时,您可以看到正确执行它需要一些工作.围绕这个名为FMDB的接口有一个瘦的Objective-C包装器,它不仅简化了与SQLite数据库的交互,而且更加强大.