【问题标题】:when to call SQLite cleanup functions?何时调用 SQLite 清理函数?
【发布时间】:2016-04-13 12:31:11
【问题描述】:

我在 iOS 中使用 sqlite 数据库。我在我的应用程序中使用了 CURD 操作。例如,将数据插入到我在下面的代码中使用的数据库中。

   - (BOOL) saveData:(User *)user
{
    const char *dbpath = [databasePath UTF8String];

    if (sqlite3_open(dbpath, &database) == SQLITE_OK)
    {
        if([self getUserData:user.email] != nil)
        {
            [self updateUserData:user];
            return YES;
        }
        else
        {
            NSString *insertSQL = [NSString stringWithFormat:
                               @"insert into users(userid,name,email,password,address,age,gender,phone,qualification,role,createddate,apiKey,priorityid,usertype) values (\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\")",user.userid,user.name,user.email,user.password,user.address,user.age,user.gender,user.phone,user.qualification,user.role,user.createddate,user.api_key,user.priority_id,user.user_type];
            NSLog(@"%@",insertSQL);
            const char *insert_stmt = [insertSQL UTF8String];
            sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
            if (sqlite3_step(statement) == SQLITE_DONE)
            {
                sqlite3_finalize(statement);
               // sqlite3_close(database);
                return YES;
        }
        else
        {
            NSLog(@"%serrr is ",sqlite3_errmsg(database));
            //sqlite3_reset(statement);
            sqlite3_close(database);
            return NO;
        }
        }
    }
    //sqlite3_reset(statement);
    sqlite3_close(database);
    return NO;
}

由于 sqlite 数据库,我的应用程序出现内存问题。我无法理解调用 sqlite3_reset();sqlite3_finalize() 的顺序, sqlite3_close()。请参考我的代码,以便我可以解决我的应用程序中的所有内存问题

编辑:

- (BOOL) insertSeMapData:(Client *)client : (NSString *)userid : (NSString *)sendemailto : (NSString *)assignworkordersto
{
    BOOL result=NO;
    const char *dbpath = [databasePath UTF8String];
    if (sqlite3_open(dbpath, &database) == SQLITE_OK)
    {
        InspectionMapDetails *inspMap = [self getSEMapData:client :userid];
        if(inspMap != nil)
        {
            [self updateSEMapData:client :userid :inspMap : sendemailto : assignworkordersto];
            result=YES;
        }
        else
        {
            const char *insert_stmt = "insert into map(inspid,inspectorid,clientid,status,createddate,sendemailreportto,assignworkordersto) values (?,?,?,?, datetime(),?,?)";
            if (sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL) == SQLITE_OK)
            {
                NSString *clientinspid=[NSString stringWithFormat:@"%@",client.inspid];
                NSString *clientid=[NSString stringWithFormat:@"%@",client.clientid];
                userid=[NSString stringWithFormat:@"%@",userid];

                sqlite3_bind_text(statement, 1, [clientinspid UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(statement, 2, [userid  UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(statement, 3, [clientid UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(statement, 4, [sendemailto  UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(statement, 5, [assignworkordersto  UTF8String], -1, SQLITE_TRANSIENT);

                if (sqlite3_step(statement) == SQLITE_DONE)
                {
                    result = YES;
                }

                sqlite3_finalize(statement);
            }
            else
            {
                NSLog(@"Unable to prepare statement: %s",sqlite3_errmsg(database));
            }

            sqlite3_close(database);
        }

    }
    else
    {
        NSLog(@"Unable to open database: %s",sqlite3_errmsg(database));
    }

    return result;
}

上述函数导致内存问题。这里 Sqlite_open 语句导致内存泄漏,我不明白为什么?

【问题讨论】:

  • 我的建议是不要使用此代码。您可以使用 sqliteManager.h 文件。
  • 然后你只需要运行插入查询。没有别的了。
  • 哦哇!你看我已经使用我的方法开发了整个应用程序,所以没有办法改变它。只需要改进。

标签: ios objective-c sqlite


【解决方案1】:

有一些简单的指导方针,坦率地说,您的代码根本不遵循其中任何一个。

对于每次成功调用sqlite3_open,您必须调用sqlite3_close

对于每次成功调用sqlite3_prepare_v2,您必须调用sqlite3_finalize。 (可选)在您重用准备好的语句的情况下,您可以调用 sqlite3_reset 零次或多次。

您应该始终检查调用sqlite3_opensqlite3_prepare_v2 的结果。如果失败,您应该使用sqlite3_errmsg 记录问题所在。

不要使用stringWithFormat 构建查询字符串。相反,使用对各种sqlite3_bind_xxx 函数的适当调用将值正确绑定到查询。

您发布的代码违反了所有这些。在很多情况下,您没有关闭数据库或完成准备好的语句。而且您错误地使用stringWithFormat: 构建查询。

您的代码已全部修复。请注意,我假设您插入的所有值都是字符串。对任何非字符串值进行相应调整。

- (BOOL) saveData:(User *)user
{
    BOOL result = NO;

    if([self getUserData:user.email] != nil)
    {
        [self updateUserData:user];
        result = YES;
    }
    else
    {
        const char *dbpath = [databasePath UTF8String];

        if (sqlite3_open(dbpath, &database) == SQLITE_OK)
        {
            const char *insert_stmt = "insert into users(userid,name,email,password,address,age,gender,phone,qualification,role,createddate,apiKey,priorityid,usertype) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

            if (sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL) == SQLITE_OK) {
                sqlite3_bind_text(stmt, 1, [user.userid UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 2, [user.name UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 3, [user.email UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 4, [user.password UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 5, [user.address UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 6, [user.age UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 7, [user.gender UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 8, [user.phone UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 9, [user.qualification UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 10, [user.role UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 11, [user.createddate UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 12, [user.api_key UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 13, [user.priority_id UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt, 14, [user.user_type UTF8String], -1, SQLITE_TRANSIENT);

                if (sqlite3_step(statement) == SQLITE_DONE)
                {
                    result = YES;
                }

                sqlite3_finalize(statement);
            }
            else
            {
                NSLog(@"Unable to prepare statement: %s",sqlite3_errmsg(database));
            }

            sqlite3_close(database);
        }
        else
        {
            NSLog(@"Unable to open database: %s",sqlite3_errmsg(database));
        }
    }

    return result;
}

基于新编辑的更新:

就像您的原始代码一样,您违反了一些规则。您更新的代码与我在上面的答案中给出的模式不太相符。

现在的主要问题是您打开了数据库,但您只在两种可能的代码路径之一下关闭它。如果inspMap != nil 你永远不会关闭数据库。

您确实应该重构代码,以便仅在 inspMapnil 时打开数据库。我在原始答案中做了类似于您的原始代码的操作。

【讨论】:

  • 谢谢,但是当我打开连接时我正在调用 close statment 并且我在完成 prepare statememt 时使用了 finilize。你能用准确的值重新发布我的代码吗?我一直在努力解决这个问题跨度>
  • 在某些情况下,但在许多情况下,您的代码在没有正确清理的情况下返回。
  • 能否请您更新我的代码,这会很棒。我不知道我做错了什么。我已经尝试解决这个问题两天了,没有希望
  • 非常感谢您的代码。我有两个疑问,为什么您没有使用 reset 语句。我在某处看到我们必须关闭数据库,无论是否成功打开。
  • 就像我说的,您需要更新您的问题,提供足够的详细信息以便人们帮助您。
猜你喜欢
  • 2020-09-12
  • 2019-10-14
  • 1970-01-01
  • 1970-01-01
  • 2020-12-16
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
相关资源
最近更新 更多