Using Fmdb multithreading to Access databases, and database is locked issues

Source: Internet
Author: User
Tags gcd

Today finally solves the problem that the database is locked when the multi-thread accesses the database simultaneously, the error message is:

Unknown error finalizing or resetting statement (5:database is locked)

Finally, through Fmdatabasequeue solves this problem, this article summarizes:

Fmdatabase cannot use the same instance for multithreading

Multi-threaded access to the database, cannot use the same Fmdatabase instance, or an exception will occur. If a thread is allowed to use a separate fmdatabase instance, there is also the possibility that the database is locked problem occurs. This is due to the competition caused by multi-thread to SQLite

My app is multithreaded using a separate Fmdatabase instance to access the database, although not caused by crash, but there is a database is locked problem, resulting in a lot of data is not written as expected

Using Fmdatabasequeue, the problem remains

Later on Fmdb's official website read the document, confirm with fmdatabasequeue can solve this problem, API is relatively simple:

NSString *dbfilepath = [Pathresolver databasefilepath];queue = [Fmdatabasequeue Databasequeuewithpath:dbfilepath]; [Queue indatabase:^ (Fmdatabase *db) {    //access db}];
But the actual test, or the database is locked

Read the relevant source code, fmdatabasequeue the idea of solving this problem is: Create a queue, and then put into the queue block order execution, so as to avoid multi-threaded simultaneous access to the database

And my code is multi-threaded each create fmdatabasequeue instances, so there are many queues, so there is still a database competition problem, and with the same as when using Fmdatabase

Share the same instance of Fmdatabasequeue

Then I let each thread use the same queue instance, and the problem is resolved.

The way to do it, I wanted to add a singleton to fmdatabase at first, but it would be troublesome to upgrade Fmdb later, so I ended up creating a helper class

@implementation losdatabasehelper{    fmdatabasequeue* queue;} -(ID) init{self    = [super init];    if (self) {        NSString *dbfilepath = [Pathresolver Databasefilepath];        Queue = [Fmdatabasequeue Databasequeuewithpath:dbfilepath];    }    return self;} + (losdatabasehelper*) sharedinstance{    static dispatch_once_t pred = 0;    __strong static id _sharedobject = nil;    Dispatch_once (&pred, ^{        _sharedobject = [[Self alloc] init];    });    return _sharedobject;} -(void) Indatabase: (void (^) (fmdatabase*)) block{    [Queue indatabase:^ (Fmdatabase *db) {        block (db);    }];} @end

Other classes in the system Use this helper class singleton, which ensures that only fmdatabasequeue instances are available globally. Note that because the helper internally holds the Fmdatabasequeue, so you can do so, if the packaging is the Fmdatabase class, there will definitely be a problem. Because Fmdatabase instances cannot be shared in a multithreaded environment

After using Fmdatabasequeue, manage db

Originally using the Fmdatabase class, you need to manually invoke the open and close methods of the DB

But with Fmdatabasequeue, you don't need to call open, because the view code finds that the queue is open. As to whether to close, I am not sure, because the official sample code did not call close. In practical applications, I did not call, as if there were no problems. If I need close, I think I can add a call to the close queue in the helper class's public methods. Here is the source of the close:

-(void) Close {    fmdbretain (self);    Dispatch_sync (_queue, ^ () {         [_db close];        Fmdbrelease (_db);        _db = 0x00;    });    Fmdbrelease (self);}

So, using queue, it is not necessary to open and close the db yourself. But if you use fmresultset,rs you need to close, otherwise you will be reported warning:

if ([db hasopenresultsets]) {    NSLog (@ "Warning:there is at least one open result set around after performing [Fmdataba Sequeue indatabase:] ");

In order not to see warning, I have called in the block [Rs Close]

Refreshing the database file path

Specific to our application, there is a special problem to consider. Because our app can switch accounts, the DB file of the account is independent. So when the user logs back in, the helper queue needs to be refreshed

+ (void) refreshdatabasefile{    losdatabasehelper *instance = [self sharedinstance];    [Instance Dorefresh];} -(void) dorefresh{    nsstring *dbfilepath = [Pathresolver Databasefilepath];    Queue = [Fmdatabasequeue Databasequeuewithpath:dbfilepath];}

If you do not, because the helper is a singleton, then after switching accounts, User B will be accessing user A's database. Refreshed calls, typically placed after login, are available before entering the main page

Queues and Threads

During the debug process, you see a phenomenon in the way. Although multiple blocks are placed in the same queue, they are actually running in different thread

Do not confuse the concept of queues and threads, when using GCD, developers focus on putting blocks into the queue, but the same queue can actually correspond to multiple threads, assigning threads to blocks, is the GCD framework, and developers do not need to pay attention. As long as the operation is put into the appropriate queue, GCD will complete the thread creation, allocation and recycling


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.