【问题标题】:iOS - SQLite insertion not inserting dataiOS - SQLite 插入不插入数据
【发布时间】:2014-02-02 14:39:58
【问题描述】:
- (id)init {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:@"idataBase.sqlite3"];
    NSLog(@"Doc path: %@",databasePath);
    bool databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
    if (!databaseAlreadyExists){
        NSString *databasePathFromApp = [[NSBundle mainBundle] pathForResource:@"idataBase" ofType:@"sqlite3"];
        NSLog(@"Main bundle path: %@",databasePathFromApp);
        [[NSFileManager defaultManager] copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
    }
    if (sqlite3_open([databasePath UTF8String], &_database) == SQLITE_OK){
        NSLog(@"Database opened");
    }dd
    return self;
}

-(void) setData:(NSDictionary *)data{
    NSLog(@"In Data %@",data);
    NSString *hostAddress = [data objectForKey:@"hostAddress"];
    NSString *userName = [data objectForKey:@"userName"];
    NSString *passKey = [data objectForKey:@"passKey"];
    NSString *listName = [data objectForKey:@"listName"];
    NSString *q = [NSString stringWithFormat:@"INSERT INTO user_info (host_name,user_name,password,text_name) VALUES (\"%@\", \"%@\", \"%@\", \"%@\")",hostAddress,userName,passKey,listName];
    NSLog(@"%@",q);
    sqlite3_stmt    *statement = NULL;
    const char *insertQuery = [q UTF8String];
    sqlite3_prepare_v2(_database, insertQuery, -1, &statement, NULL);
    if(sqlite3_step(statement) == SQLITE_OK){
        NSLog(@"Data Inserted");
    }
    sqlite3_finalize(statement);
    sqlite3_close(_database);

}

我正在使用上面的代码插入数据。数据库连接在 init 方法中打开。但我无法在数据库中插入数据。 sqlite3_step(statement) 从不返回 SQLITE_OK。

【问题讨论】:

  • 第一个主要问题 - 您正在使用 stringWithFormat 构建查询。不要那样做。正确使用sqlite3_bind_xxx 将值绑定到您的查询中。并在出现故障时使用sqlite3_errmsg 记录错误。并检查对sqlite3_prepare_v2 的调用结果。我在您关于删除数据的最后一个问题中提到了大部分内容。您需要进行适当的错误检查。
  • @rmaddy 谢谢。它显示了一些错误“库例程调用乱序”
  • 您没有解决我在其他问题中指出的其他问题。您对sqlite3_opensqlite3_close 的呼叫仍然不平衡。此类是否有其他适用于数据库的方法?确保所有方法正确调用preparestepfinalize。并将close 放入dealloc 方法中。
  • 并考虑使用 FMDB 代替原始 sqlite。
  • rmaddy 说 FMDB 值得考虑是对的,因为它极大地简化了您的流程。值得注意的是,如果使用 C 接口,在 SQL 中使用 ? 占位符(这非常重要)需要大量的 sqlite3_bind_xxx 调用,但 FMDB 消除了这个过程的痛苦。

标签: ios sqlite


【解决方案1】:

你说:

sqlite3_step(statement) 从不返回 SQLITE_OK。

正确,如果成功,则返回SQLITE_DONE(在执行插入/更新/删除查询时)。见sqlite3_step documentation

如果您没有收到SQLITE_DONE,那么您应该检查sqlite3_errmsg 以确定原因。如果它报告“按顺序调用的库例程”错误,这可能意味着sqlite3_prepare_v2 失败,它实际上是在说它看到sqlite3_step 而没有成功的sqlite3_prepare_v2 调用。

因此,您还应该检查sqlite3_prepare_v2 的结果(即,更频繁地,问题的根源)并确保它是SQLITE_OK,如果不是,请立即查看sqlite3_errmsg,之前打电话给sqlite3_step。如果您收到来自sqlite3_prepare_v2 的错误并忽略该错误并只调用sqlite3_step,您将丢失在调用sqlite3_step 之前可以检查的有意义的错误消息,将有意义的错误消息替换为“名为乱序”错误。


这纯属猜想,但鉴于您对复制数据库问题的其他问题,我可能会打赌,在您的测试中的某个时间,您运行的代码副本未能复制数据库,但仍继续调用sqlite3_open。如果找不到,sqlite3_open 将创建一个空白数据库。因此,如果数据库是空白的,我不会感到惊讶,因此来自sqlite3_prepare_v2 的错误消息将报告找不到该表。如果我的猜想是正确的(sqlite3_prepare_v2 失败并且调用sqlite3_errmsg 报告找不到该表),我建议从您的模拟器/设备中删除该应用程序(删除位于Documents 中的任何空白数据库文件夹)并尝试再次运行该应用程序。如果捆绑包中的副本失败,我还将确保您的代码不会尝试打开数据库(否​​则您将面临再次创建空白数据库的风险)。我可能还建议将您的 sqlite3_open 代码替换为:

if (sqlite3_open_v2([databasePath UTF8String], &_database, SQLITE_OPEN_READWRITE, NULL) == SQLITE_OK)
    NSLog(@"Database opened");

这就像sqlite3_open,但如果找不到,这不会创建一个空白数据库。


因此,检查所有 SQLite 返回码并在 SQL 中使用 ? 占位符的例程可能如下所示:

- (void)insertUserInfo:(NSDictionary *)dictionary
{
    NSString *hostAddress = dictionary[@"hostAddress"];
    NSString *userName    = dictionary[@"userName"];
    NSString *passKey     = dictionary[@"passKey"];
    NSString *listName    = dictionary[@"listName"];

    const char *sql = "INSERT INTO user_info (host_name,user_name,password,text_name) VALUES (?, ?, ?, ?)";

    sqlite3_stmt *statement = NULL;

    if (sqlite3_prepare_v2(_database, sql, -1, &statement, NULL) != SQLITE_OK) {
        NSLog(@"prepare failed: %s", sqlite3_errmsg(_database));
        return;
    }

    if (![self bindString:hostAddress column:1 statement:statement])
        return;

    if (![self bindString:userName column:2 statement:statement])
        return;

    if (![self bindString:passKey column:3 statement:statement])
        return;

    if (![self bindString:listName column:4 statement:statement])
        return;

    if (sqlite3_step(statement) == SQLITE_DONE) {
        NSLog(@"Data Inserted");
    } else {
        NSLog(@"Insert failed: %s", sqlite3_errmsg(_database));
    }
    sqlite3_finalize(statement);
}

将字符串值绑定到列的方法可能如下所示:

- (BOOL)bindString:(NSString *)value column:(NSInteger)column statement:(sqlite3_stmt *)statement
{
    if (value) {
        if (sqlite3_bind_text(statement, column, [value UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
            NSLog(@"bind column %d to %@ failed: %s", column, value, sqlite3_errmsg(_database));
            sqlite3_finalize(statement);
            return NO;
        }
    } else {
        if (sqlite3_bind_null(statement, column) != SQLITE_OK) {
            NSLog(@"bind column %d to null failed: %s", column, sqlite3_errmsg(_database));
            sqlite3_finalize(statement);
            return NO;
        }
    }

    return YES;
}

【讨论】:

  • 很抱歉这样敲你。但是我被一个问题困扰了很长时间。我不知道我在这里错过了什么。我真的很抱歉先生。如果你有时间,请看这个:stackoverflow.com/questions/33852420/… 这将是一个很大的帮助。除了你,我不知道有谁能帮忙。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-18
  • 2011-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多