【问题标题】:issue during insert data by using sqlite3 in to db iPhone使用 sqlite3 在 db iPhone 中插入数据时出现问题
【发布时间】:2012-12-05 17:09:18
【问题描述】:

我遇到了一个问题,我试图将来自 NSMutableArray 的数据插入到我的数据库中。这是我到目前为止所拥有的:

- (void)insertList:(NSString*) strListName ArrayOfData:(NSMutableArray*) dataArray{
sqlite3 *database = nil;
sqlite3_stmt *addStmt = nil;

NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"customlists.sqlite"];
if(sqlite3_open([defaultDBPath UTF8String], &database) == SQLITE_OK)
{
    for (int i = 0; i < dataArray.count; i++)
    {
        PageData *pageDta = [PageData new];
        pageDta = [dataArray objectAtIndex:i];

        if(addStmt == nil) {
            const char *sql = "insert into NewList(ListName, PageName, PageNumber, id) Values(?, ?, ?, ?)";
            if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
                NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(database));
        }

        sqlite3_bind_text(addStmt, 1, [strListName UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(addStmt, 2, [pageDta.strNamebyFilter UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(addStmt, 3, [pageDta.strPageNuber UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_int(addStmt, 4, i);

        if(SQLITE_DONE != sqlite3_step(addStmt))
            NSAssert1(0, @"Error while inserting data. '%s'", sqlite3_errmsg(database));
        else
            //SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid
            sqlite3_last_insert_rowid(database);

        //Reset the add statement.
        sqlite3_reset(addStmt);
    }
}
else
{
    NSLog(@"Error while opening database '%s'", sqlite3_errmsg(database));
}
sqlite3_close(database);
}

但是调用这个函数后,数据库是空的。有人可以帮我找出这个问题的原因和潜在的补救措施吗?

【问题讨论】:

  • 有太多代码开始思考问题出在哪里......也许您可以调试它或将问题减少到代码的某些部分。如果您将此代码粘贴到 stackoverflow 中等待答案,您将不会获得太多帮助...祝您好运!
  • 你有输出日志吗?还是什么也没发生? !
  • 实际上函数运行成功,没有错误,所以没有什么要调试的。
  • 调试工具不仅在您发现错误时使用,大多数时候如果您不知道发生了什么,它会很有帮助...
  • 看看我的回答:stackoverflow.com/questions/13060166/sqlite-ios-insert-data,希望对你有帮助:)

标签: iphone objective-c ios xcode sqlite


【解决方案1】:

主要问题很简单 - 您正在尝试写入应用程序包中的数据库。这是不允许的。应用程序的包在真实设备上是只读的(尽管它在模拟器中是可写的)。正确的做法是在应用程序第一次运行时将数据库从资源包复制到应用程序沙箱的可写区域。然后数据库的每次使用都以副本完成。

在for 循环之前准备语句也会更简洁。无需在每次循环迭代时检查它是否已设置。

您拨打了sqlite3_last_insert_rowid 的电话,但没有对该值做任何事情。有什么意义?

循环完成后,您永远不会完成语句。你需要这样做。

完成后您不会关闭数据库。

【讨论】:

    【解决方案2】:

    改变这一行:

    const char *sql = "insert into NewList(ListName, PageName, PageNumber, id) Values(?, ?, ?, ?)";
    

    到:

    NSString *insertSQL = [NSString stringWithFormat: @"NSString stringWithFormat: "INSERT INTO  NewList(ListName, PageName, PageNumber, id) VALUES(\"%@\", \"%@\", \"%@\", \"%@\")" ,strListName, pageDta.strNamebyFilter, pageDta.strPageNuber, addStmt];
    
    const char *sql = [insertSQL UTF8String];
    

    【讨论】:

    • 我有下一个错误:[49304:c07] *** 断言失败 -[DBManager insertNewList:ArrayOfData:], /Users/admin/Documents/DBManager.m:85
    • 这是创建查询字符串的最糟糕的方法。切勿为此使用字符串格式。
    • 您能提供更好的方法吗?
    • @Roman 你已经在做正确的事情了。使用 ?然后在查询中将值绑定到语句。
    • 我应该补充一下为什么鲁迪的回答不好。首先,文本值需要用单引号,而不是双引号。此外,当其中一个字符串值包含引号时会发生什么?这就是 SQL 注入安全漏洞的产生方式。通过对每个值使用带有问号的查询字符串并调用sqlite3_bind_xxx,该库会处理所需的任何引用和转义。它消除了一整套可能的错误和安全问题。
    【解决方案3】:

    我已将函数重写为:

     if(sqlite3_open([defaultDBPath UTF8String], &database) == SQLITE_OK)
    {
        for (int i = 0; i < dataArray.count; i++)
        {
            PageData *pageDta = [PageData new];
            pageDta = [dataArray objectAtIndex:i];
    
            if(addStmt == nil) {
                const char *sql = [[NSString stringWithFormat:@"INSERT INTO NewList (ListName, PageName, PageNumber) values('%@', '%@', '%@')",strListName,pageDta.strNamebyFilter, pageDta.strPageNuber] UTF8String];
    
                if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
                    NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(database));
            }
    
            sqlite3_bind_text(addStmt, 1, [strListName UTF8String], -1, SQLITE_TRANSIENT);
            sqlite3_bind_text(addStmt, 2, [pageDta.strNamebyFilter UTF8String], -1, SQLITE_TRANSIENT);
            sqlite3_bind_text(addStmt, 3, [pageDta.strPageNuber UTF8String], -1, SQLITE_TRANSIENT);
    
            if(SQLITE_DONE != sqlite3_step(addStmt))
                NSAssert1(0, @"Error while inserting data. '%s'", sqlite3_errmsg(database));
    
            //Reset the add statement.
            sqlite3_reset(addStmt);
        }
        sqlite3_finalize(addStmt);
    }
    else
    {
        NSLog(@"Error while opening database '%s'", sqlite3_errmsg(database));
    }
    sqlite3_close(database);   
    

    但结果是一样的:(

    【讨论】:

    • 您应该使用此信息更新您的问题,而不是将其作为答案发布。您似乎忽略了我的主要陈述-您无法写入资源包中的数据库。您没有移动准备语句。您的查询字符串仍然不正确。您试图在不包含任何 ? 的查询上调用 sqlite3_bind_text里面的人物。您的原始查询字符串是正确的。不要使用 stringWithFormat 来创建查询。
    猜你喜欢
    • 2017-10-04
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    相关资源
    最近更新 更多