I believe that my use case is fairly common, but I could not find an authoritative answer for this.
I have a sync mechanism that runs in background and write data to my database. This sync can take a lot of time (I use FTS). For this I use a FMDatabaseQueue
. When I want to read on the database, I use the same queue to make a query.
Now, when the sync process already queued a lot of transactions to the queue then the app wants to do a read, it has to wait for all the write transactions to finish before being able to do a query, as this is a serial queue. The code might look like this:
FMDatabaseQueue *queue = [self getDatabaseQueue];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Very slow process
[db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Very slow process
[db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Very slow process
[db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[queue inDatabase:^(FMDatabase *db) {
FMResultSet *resultSet = [db executeQuery:@"SELECT name..."];
}];
I want to have the query results instantaneously (even if the sync is not done) and not wait to the UPDATE
to be done.
Can I create two FMDatabaseQueue
s, one for the write queries and one for the read queries? What will happen if a read query starts right in the middle of a write transaction?
The code might look like this:
FMDatabaseQueue *writeQueue = [self getWriteDatabaseQueue];
FMDatabaseQueue *readQueue = [self getReadDatabaseQueue];
[writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Very slow process
[db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Very slow process
[db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Very slow process
[db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[readQueue inDatabase:^(FMDatabase *db) {
FMResultSet *resultSet = [db executeQuery:@"SELECT name..."];
}];
Edit:
Also, what confuses me is the documentation which states:
It has always been OK to make a FMDatabase object per thread. Just don't share a single instance across threads.
So what I understand from that is that I can create two isntances with the same database but that I just need to keep it on their own thread.