javiazo
javiazo

Reputation: 1982

sqlite3 - iOS - database is locked

I am developing an app for ipad and i am using sqlite sentences (select, update, insert, delete).

I open (sqlite3_open) the database at the beginning and close (sqlite3_close) at the end of each sentence. But sometimes i´ve got the "database is locked" message.

I don´t know what can i do to solve this.

Thanks and sorry for this little information.

Upvotes: 4

Views: 13507

Answers (4)

asawadhesh singh
asawadhesh singh

Reputation: 1

it is use for three methed 1.isert 2.update 3. delete.

-(NSMutableArray *)resultSet
-(void)insertWithTitle:(NSString *)title Body:(NSString *)body
-(BOOL)updateAtIndex:(int)index Title:(NSString *)title Body:(NSString *)body

NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:0] autorelease];

FMResultSet *rs = [db executeQuery:[self SQL:@"SELECT * FROM %@" inTable:TABLE_NAME]];
while ([rs next]) {
    Record *tr = [[Record alloc] initWithIndex:[rs intForColumn:@"id"]
                                         Title:[rs stringForColumn:@"title"]
                                          Body:[rs stringForColumn:@"body"]];
    [result addObject:tr];
    [tr release];
}

[rs close];

2....

return result;
[db executeUpdate:[self SQL:@"INSERT INTO %@ (title, body) VALUES (?,?)" inTable:TABLE_NAME], title, body];
if ([db hadError]) {
    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);

Delete record :

BOOL success = YES;
[db executeUpdate:[self SQL:@"DELETE FROM %@ WHERE id = ?" inTable:TABLE_NAME], [NSNumber numberWithInt:index]];
if ([db hadError]) {
    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
    success = NO;
}
return success;

}

Upvotes: -1

Serguei Fedorov
Serguei Fedorov

Reputation: 7913

A good way to solve this is to wrap this into a C++ library. This way, you can can create the library wrapper on the stack. This means that the moment that the function goes out of scope, you can close the connection in the destructor.

(note that I use reference counting for the Objective-C)

For instance:

NSArray* ScoreBoard::getAllScores()
{ 
      ScoreBoard::ensureExistingTable();

      //Stack allocated
      SqliteWrapper sqlite("Scores.sqlite");

     NSArray* result = sqlite.RunQuery("SELECT * FROM Scores ORDER BY ID DESC");

     return result;
     //after this, the sqlite destructor is called
}

It is very nice that the Objective-C compiler allows you to merge C++. It can be extremely useful.

Also

 void SqliteWrapper::Close()
 {
     sqlite3_close(db);
 }

as Vincent has pointed out, you have to finalize the statement. If you want keep the connection open, use finalize after each statement. Close out the connection the moment you are discarding the connection.

This method works for me.

Upvotes: 0

Vincent
Vincent

Reputation: 4409

You probably opened the database before using the same simulator. To conclude all actions to a database and release all resources you always have to use both (!) statements:

sqlite3_finalize(statement);
sqlite3_close(database);

Upvotes: 3

George
George

Reputation: 4029

If I'm not mistaken , the problem with sqllite is that you can only access it once at a time. If you have multiple threads, you can run in this situation. Example:

Run method1 (which accesses the database) on thread t1. Run method2 (which accesses the database) on thread t2 after x seconds.

If method1 is not finished in those x seconds , both methods will access it at the same time. And , as I said , I know that sqllite does not support this.

You should try to flag the usage of your database and if you want to access it but it is in use , try again after x seconds. Like this:

- (void) generalMethodThatUsesDatabses
{
    if(databaseIsUsed)
    {
         [self performSelector:@selector(generalMethodThatUsesDatabses) withObject:nil afterDelay:5];
          return;
    }

    databaseIsUsed = TRUE;   //global bool variable


    //your code here

    databaseIsUsed = FALSE;

}

Hope this helps. Cheers!

Upvotes: 7

Related Questions