FMDatabase is currently in use on concurrent execution - ios

Am doing preloading the datas from service in my mobile application.
Here I added around 7 service in NSOperationQueue and all these operations result will update the DataBase.
Here while updating the database am getting warning in log like "FMDatabase is currently in use" and datas have not been inserted into DB.
Here how to handle this problem in concurrent execution and updating the database.

I didn't use FMDatabase, but you have to read it's documentation
It is part of the doc:
So don't instantiate a single FMDatabase object and use it across
multiple threads.
Instead, use FMDatabaseQueue. It's your friend and it's here to help.

Related

FMDB block my UI

Fmdb in iOS, I have a task to convert 100 JSON string to my model from network and then represent them on the UITableViewCell, because I have 3 button to change the data on the UITableView , so I fmdb the data to local, when I change the data it first check to read the local data, and then request newest data to reload UITableView and save to database. All 3 changes have the same logic. Because 100 data to store I choose to asynchronous dispatch the for statement, then the problem is when the model inserts in to table it stuck my UI a little bit. My table has 10+ columns , is there any possibility just because too much columns cause insert assume too much time?
According to FMDB documentation, it's better to use FMDatabaseQueue for your case.
To perform queries and updates on multiple threads, you’ll want to use FMDatabaseQueue.
Using a single instance of FMDatabase from multiple threads at once is a bad idea. It has always been OK to make a FMDatabase object per thread. Just don’t share a single instance across threads, and definitely not across multiple threads at the same time.
Instead, use FMDatabaseQueue.
Here's the reference.

sqlite issue in iOS accessing two table at same time

I hope all doing well, I have one query regarding the sqlite .
Is that possible that two different sqlite table access at ones .
ex.
I have table A ans B .Can access A and B at same time .insert updating table value .
I have two different table,Table1 and table2 in myDatabase( test_db.sqlite).
Table 1 is only access by main thread.
Table 2 will be only access by background thread.
Now let c.
I have open the database connection using background thread…for inserting the value into table2.
while inserting the value into table2………….my main thread tries to open the same database connection at the same time to retrieve the data from table 1……and the app crash.
how to open the same database connection concurrently.
please check this edit one
[EDIT]
You are getting problems by accessing the Database in different threads. You can deal with this problem by using thread safe mode.
From SQL docs:
SQLite support three different threading modes:
Single-thread. In this mode, all mutexes are disabled and SQLite is unsafe to use in more than a single thread at once.
Multi-thread. In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.
Serialized. In serialized mode, SQLite can be safely used by multiple threads with no restriction.
So, you can use the SQLITE_THREADSAFE compile-time parameter to select the threading mode.
I suggest that you open a different DB connection in each thread, or rebuild SQLite in serialised mode (with SQLITE_THREADSAFE=1).
OLD Answer:
It's difficult to answer your problem if you do not provide the exact error you are receiving. But, making the assumption that your queries are ok, the most probable cause is that you are not handling your sqlite flow correctly.
I suppose that your problem is that you are updating table "A" and then when trying to update table "B" it crashes. That's why you are trying to create a single query to update both of them.
So, before reusing your sqlite3_stmt to make the second query, you should, first, call sqlite3_finalize(yourStatement) to release the statement from memory, and then, if you want to make the second query just call sqlite3_prepare_v2 again, so the database is ready to accept the next query after that.

How to handle multiple thread access the sqlite3 with out dblocked error

In my application, background sqlite thread is running... in background thread it fetching data from web service and insert or update data into database. if user insert or delete data from foreground,sometimes i am getting crash it display "sqlite dblocked". but it does not return sqlite busy error.
And i tested thread safe mode
NSLog(#" sqlite3_threadsafe() = %d", sqlite3_threadsafe());
it display threadsafe is 2.
I want to check if any other db is writing data, if db is writing data.. i want to write data after previous write task is finished.
how to handle these situation..
You can use lock (such as those enumerated in the Synchronization section of the Threading Programming Guide) or you can use a dedicated serial queue. For example, create a queue:
#property (nonatomic, strong) dispatch_queue_t databaseQueue;
Instantiate it:
self.databaseQueue = dispatch_queue_create("com.company.app.database", 0);
And whenever you want to interact with the database, you can do
dispatch_sync(self.databaseQueue, ^{
// do your database activity here
});
If you want to simplify your life, the FMDB library has a FMDatabaseQueue object that does much of this for you (as well as greatly simplifying your database interaction in general).
The thread safe mode prevents crashed when multiple threads access the same connection, but it cannot prevent multiple connections from interfering with each other.
You should use a common lock to protect all database transactions; use either a mutex or the #synchronized directive.
From the SQLite docs:
Use the SQLITE_THREADSAFE compile-time parameter to selected the threading mode. If no SQLITE_THREADSAFE compile-time parameter is present, then serialized mode is used. This can be made explicit with -DSQLITE_THREADSAFE=1. With -DSQLITE_THREADSAFE=0 the threading mode is single-thread. With -DSQLITE_THREADSAFE=2 the threading mode is multi-thread.
So it seems you have SQLite in multithreaded mode, but not serialised. In this mode, you cannot use the same database connection from different threads, but you will be safe if you open a different connection in each thread.

Sqlite3 Concurrency Issue in IOS

I am using SQLite 3 in my iOS application. It requires lots of read/write operation and many of them attempted concurrently. Most of these functions are running in separate threads, however accessing same database.
Here are few methods I have thought of:
At every database access ( read/write ) I put a flag as database_open=YES, and if it is found true I retry again in few seconds. I can put the function at the database layer itself.
Run all database operations in same thread. However, my use case is such that I need to wait for some HTTP calls to finish and store the retreived data into SQLite. For this method, I will have to make all these server calls as well synchronous. Not the best idea.
Please suggest if I am thinking in wrong direction.
SQLite supports concurrent access from multiple threads. Simply configure the SQLITE_CONFIG_MULTITHREAD mode, and separately open the database from each of the threads.

Is it necessary to lock simultaneous SQLite access for SELECT statements?

I am using FMDB to access the standard iOS internal SQLite database, with one db connection shared among multiple threads.
To make it thread safe I'm locking access to the db to one block of code at a time. All works well, although the access to the db is now a bit of a bottleneck, obviously.
My question is: Can I ease this up a bit by allowing simultaneous queries from multiple threads, as long as they are all readonly SELECT statements?
I can't find an answer anywhere.
You cannot use the same connection to execute multiple queries at the same time.
However, for purely read-only accesses, you can use multiple connections.
You can have one FMDatabase object for each thread. You might have to write code to test for genuine busy conditions and handle them properly. For example set busyRetryTimeout appropriate for your situation (e.g. how long do you want it to retry in contention situations). Also gracefully handle if the timeout expires and your database query fails.
Clearly, using a shared FMDatabaseQueue is the easiest way to do database interactions from multiple threads. See the Using FMDatabaseQueue and Thread Safety section of the FMDB README.

Resources