Reputation: 1641
I am going through the most common problem of database getting locked.
When my app runs an api is hit to fetch data. This data is then inserted into database table. I am doing this in a background thread with a serial queue. In the meantime if user presses the button to switch to the next screen, select query works(on main thread) to get the data to be displayed. That's the point when I get this issue. Even the app crashes at times.
I have searched this problem but everytime I get to see either a link to the tutorial about 'synchronisation' or using FMDB.
As I am running out of time, can somebody plz help me to provide a simple and detailed solution. Also I am posting my code meant to insert and retrieve data. Plz care to check if I am going wrong somewhere.
-(void)insertIntoTable_VENUES_WithData:(NSArray*)dataArray{
sqlite3_stmt *statement = nil;
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_database) == SQLITE_OK) {
const char *sql = "INSERT OR REPLACE INTO venues (gig_date, start_time, doors_open, end_time, gig_title, main_artist, gig_type, promoter, band_members, venue, tel_no, postcode, img_url, ticket_price, booking_url, sold_out, venue_url, venue_biog, sync_flag) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setLocale:[[StaticHelper sharedObject] usLocale]];
if (sqlite3_prepare_v2(_database, sql, -1, &statement, NULL) == SQLITE_OK) {
for (int i=0; i<dataArray.count; i++) {
NSDictionary *dataDic = [NSDictionary dictionaryWithDictionary:[dataArray objectAtIndex:i]];
if (![[dataDic objectForKey:kGigDate] isEqual:[NSNull null]]){
NSString *dateStr = [dataDic objectForKey:kGigDate];
[dateFormat setDateFormat:@"dd/MM/yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormat dateFromString:dateStr];
NSDate *dateWithoutTime = [[StaticHelper sharedObject] getDateWithOutTime:dateFromString];
float dateToStore = [dateWithoutTime timeIntervalSince1970];
sqlite3_bind_double(statement, 1, dateToStore);
}
else
sqlite3_bind_null(statement,1);
if (![[dataDic objectForKey:kStartTime] isEqual:[NSNull null]])
sqlite3_bind_text(statement,2,[[dataDic objectForKey:kStartTime] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,2);
if (![[dataDic objectForKey:kDoorsOpen] isEqual:[NSNull null]])
sqlite3_bind_text(statement,3,[[dataDic objectForKey:kDoorsOpen] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,3);
if (![[dataDic objectForKey:kEndTime] isEqual:[NSNull null]])
sqlite3_bind_text(statement,4,[[dataDic objectForKey:kEndTime] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,4);
if (![[dataDic objectForKey:kGigTitle] isEqual:[NSNull null]])
sqlite3_bind_text(statement,5,[[dataDic objectForKey:kGigTitle] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,5);
if (![[dataDic objectForKey:kMainArtist] isEqual:[NSNull null]])
sqlite3_bind_text(statement,6,[[dataDic objectForKey:kMainArtist] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,6);
if (![[dataDic objectForKey:kGigType] isEqual:[NSNull null]])
sqlite3_bind_text(statement,7,[[dataDic objectForKey:kGigType] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,7);
if (![[dataDic objectForKey:kPromoter] isEqual:[NSNull null]])
sqlite3_bind_text(statement,8,[[dataDic objectForKey:kPromoter] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,8);
if (![[dataDic objectForKey:kBandMembers] isEqual:[NSNull null]])
sqlite3_bind_text(statement,9,[[dataDic objectForKey:kBandMembers] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,9);
if (![[dataDic objectForKey:kVenue] isEqual:[NSNull null]])
sqlite3_bind_text(statement,10,[[dataDic objectForKey:kVenue] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,10);
if (![[dataDic objectForKey:kTelNo] isEqual:[NSNull null]])
sqlite3_bind_text(statement,11,[[dataDic objectForKey:kTelNo] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,11);
if (![[dataDic objectForKey:kPostCode] isEqual:[NSNull null]])
sqlite3_bind_text(statement,12,[[dataDic objectForKey:kPostCode] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,12);
if (![[dataDic objectForKey:kImgUrl] isEqual:[NSNull null]])
sqlite3_bind_text(statement,13,[[dataDic objectForKey:kImgUrl] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,13);
if (![[dataDic objectForKey:kTicketPrice] isEqual:[NSNull null]])
sqlite3_bind_text(statement,14,[[dataDic objectForKey:kTicketPrice] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,14);
if (![[dataDic objectForKey:kBookingUrl] isEqual:[NSNull null]])
sqlite3_bind_text(statement,15,[[dataDic objectForKey:kBookingUrl] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,15);
if (![[dataDic objectForKey:kSoldOut] isEqual:[NSNull null]])
sqlite3_bind_text(statement,16,[[dataDic objectForKey:kSoldOut] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,16);
if (![[dataDic objectForKey:kVenueUrl] isEqual:[NSNull null]])
sqlite3_bind_text(statement,17,[[dataDic objectForKey:kVenueUrl] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,17);
if (![[dataDic objectForKey:kVenueBlog] isEqual:[NSNull null]])
sqlite3_bind_text(statement,18,[[dataDic objectForKey:kVenueBlog] UTF8String],-1,SQLITE_TRANSIENT);
else
sqlite3_bind_null(statement,18);
sqlite3_bind_int(statement, 19, 0);////
if (sqlite3_step(statement) != SQLITE_DONE) {
NSLog(@"SQL execution failed in ZADDED_FOOD_ITEMS: %s", sqlite3_errmsg(_database));
}
if (sqlite3_step(statement) == SQLITE_DONE) {
if (i == (dataArray.count - 1))
sqlite3_finalize(statement);
}else{
sqlite3_reset(statement);
NSLog(@"SQL execution failed: %s", sqlite3_errmsg(_database));
}
}//for
sqlite3_finalize(statement);
}else{
NSLog(@"Row insertion error(error in prepare!)");
}
sqlite3_finalize(statement);//finalize is to sqlite3_prepare_v2 as close is to sqlite3_open
sqlite3_close(_database);;
}else{
NSLog(@"error in opening db");
}
}
-(NSMutableArray *)getDataFromTable_VENUES_WhereGigDateIsEqualTo:(NSDate*)gigDate
{
NSDate *dateWithoutTime = [[StaticHelper sharedObject] getDateWithOutTime:gigDate];
NSTimeInterval dateInterval = [dateWithoutTime timeIntervalSince1970] ;
NSInteger intDateInterval = dateInterval;
const char *dbpath = [_databasePath UTF8String];
NSMutableArray *queryResult = [NSMutableArray array];
sqlite3_stmt *statement = nil;
NSMutableDictionary *dic;
if (sqlite3_open(dbpath, &_database) == SQLITE_OK)
{
NSString *query = [NSString stringWithFormat:@" SELECT * FROM %@ WHERE %@='%ld' AND %@=1 ORDER BY %@ ASC ",kVenues, kGigDate, intDateInterval, kSyncFlag, kStartTime];
if(sqlite3_prepare_v2(_database,[query UTF8String],-1,&statement,NULL)==SQLITE_OK)
{
while (sqlite3_step(statement)<=SQLITE_ROW)
{
dic = [NSMutableDictionary dictionary];
float dbDataAsDouble0 = sqlite3_column_double(statement, 0);
NSDate *dateRetrieved = [NSDate dateWithTimeIntervalSince1970:dbDataAsDouble0];
NSString *strDate = [[StaticHelper sharedObject] getStringFromDate:dateRetrieved];
//char *dbDataAsChars0 = (char*)sqlite3_column_text(statement, 0);
if (strDate != nil)
[dic setObject:strDate forKey:kGigDate];
else{
[dic setObject:@"" forKey:kGigDate];
}
char *dbDataAsChars1 = (char*)sqlite3_column_text(statement, 1);
if (dbDataAsChars1 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars1] forKey:kStartTime];
else{
[dic setObject:@"" forKey:kStartTime];
}
char *dbDataAsChars2 = (char*)sqlite3_column_text(statement, 2);
if (dbDataAsChars2 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars2] forKey:kDoorsOpen];
else{
[dic setObject:@"" forKey:kDoorsOpen];
}
char *dbDataAsChars3 = (char*)sqlite3_column_text(statement, 3);
if (dbDataAsChars3 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars3] forKey:kEndTime];
else{
[dic setObject:@"" forKey:kEndTime];
}
char *dbDataAsChars4 = (char*)sqlite3_column_text(statement, 4);
if (dbDataAsChars4 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars4] forKey:kGigTitle];
else{
[dic setObject:@"" forKey:kGigTitle];
}
char *dbDataAsChars5 = (char*)sqlite3_column_text(statement, 5);
if (dbDataAsChars5 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars5] forKey:kMainArtist];
else{
[dic setObject:@"" forKey:kMainArtist];
}
char *dbDataAsChars6 = (char*)sqlite3_column_text(statement, 6);
if (dbDataAsChars6 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars6] forKey:kGigType];
else{
[dic setObject:@"" forKey:kGigType];
}
char *dbDataAsChars7 = (char*)sqlite3_column_text(statement, 7);
if (dbDataAsChars7 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars7] forKey:kPromoter];
else{
[dic setObject:@"" forKey:kPromoter];
}
char *dbDataAsChars8 = (char*)sqlite3_column_text(statement, 8);
if (dbDataAsChars8 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars8] forKey:kBandMembers];
else{
[dic setObject:@"" forKey:kBandMembers];
}
char *dbDataAsChars9 = (char*)sqlite3_column_text(statement, 9);
if (dbDataAsChars9 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars9] forKey:kVenue];
else{
[dic setObject:@"" forKey:kVenue];
}
char *dbDataAsChars10 = (char*)sqlite3_column_text(statement, 10);
if (dbDataAsChars10 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars10] forKey:kTelNo];
else{
[dic setObject:@"" forKey:kTelNo];
}
char *dbDataAsChars11 = (char*)sqlite3_column_text(statement, 11);
if (dbDataAsChars11 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars11] forKey:kPostCode];
else{
[dic setObject:@"" forKey:kPostCode];
}
char *dbDataAsChars12 = (char*)sqlite3_column_text(statement, 12);
if (dbDataAsChars12 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars12] forKey:kImgUrl];
else{
[dic setObject:@"" forKey:kImgUrl];
}
char *dbDataAsChars13 = (char*)sqlite3_column_text(statement, 13);
if (dbDataAsChars13 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars13] forKey:kTicketPrice];
else{
[dic setObject:@"" forKey:kTicketPrice];
}
char *dbDataAsChars14 = (char*)sqlite3_column_text(statement, 14);
if (dbDataAsChars14 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars14] forKey:kBookingUrl];
else{
[dic setObject:@"" forKey:kBookingUrl];
}
char *dbDataAsChars15 = (char*)sqlite3_column_text(statement, 15);
if (dbDataAsChars15 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars15] forKey:kSoldOut];
else{
[dic setObject:@"" forKey:kSoldOut];
}
char *dbDataAsChars16 = (char*)sqlite3_column_text(statement, 16);
if (dbDataAsChars16 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars16] forKey:kVenueUrl];
else{
[dic setObject:@"" forKey:kVenueUrl];
}
char *dbDataAsChars17 = (char*)sqlite3_column_text(statement, 17);
if (dbDataAsChars17 != NULL)
[dic setObject:[NSString stringWithUTF8String:dbDataAsChars17] forKey:kVenueBlog];
else{
[dic setObject:@"" forKey:kVenueBlog];
}
[queryResult addObject:dic];
}
sqlite3_finalize(statement);
}
else{
////NSLog(@"Error msg : %s ", sqlite3_errmsg(_database));
return nil;
}
sqlite3_close(_database);
}
else{
NSLog(@"database not open : %s",sqlite3_errmsg(_database));
}
return queryResult;
}
Upvotes: 0
Views: 421
Reputation: 3446
If database already open and locked with some thread -process, it gives this error when you try to open it (Try to open locked database)
In you getDataFromTable_VENUES_WhereGigDateIsEqualTo
method,Check following:
else{
////NSLog(@"Error msg : %s ", sqlite3_errmsg(_database));
return nil;
}
Here, you are returing without unlocking open database with
sqlite3_close(_database);
close database before return here. also check for similar problem everywhere else in your code.
else{
sqlite3_close(_database);
////NSLog(@"Error msg : %s ", sqlite3_errmsg(_database));
return nil;
}
to avoid similar error, create class for handling database functions and create shared instance of it.
#import <Foundation/Foundation.h>
#import <sqlite3.h>
@interface DBManager : NSObject
{
NSString *databasePath;
}
+(DBManager*)getSharedInstance;
@end
#import "DBManager.h"
static DBManager *sharedInstance = nil;
static sqlite3 *database = nil;
static sqlite3_stmt *statement = nil;
@implementation DBManager
+(DBManager*)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
[sharedInstance openDB];
}
return sharedInstance;
}
-(BOOL)openDB{
//Code to open database, assign that to database
, return status
}
Upvotes: 1
Reputation: 983
You are opening your data base everytime before any query. Make one method to open database and open your connection in app launch.
- (void) openDatabaseConnection
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:yourDB];
if (sqlite3_open_v2([path UTF8String], &databaseName, SQLITE_OPEN_READWRITE, NULL) == SQLITE_OK)
{
NSLog(@"Data base connection opened %@",path);
}
else
{
NSLog(@"Error in opening database :(");
}
}
Don't open it every time. It will lock your database for frequent connection open and close.
Upvotes: 1