Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQLiteDatabaseLockedException: database is locked (code 5) #191

Closed
KushGoyal opened this issue Jun 3, 2015 · 22 comments
Closed

SQLiteDatabaseLockedException: database is locked (code 5) #191

KushGoyal opened this issue Jun 3, 2015 · 22 comments

Comments

@KushGoyal
Copy link

Some of my users are facing SQLiteDatabaseLockedException.

I am using this code in my application class onCreate method to setup database:

private void setupDatabase() {
        DbUpdateHelper helper = new DbUpdateHelper(this, "app-name-db", null);
        SQLiteDatabase db = helper.getWritableDatabase();
        DaoMaster daoMaster = new DaoMaster(db);
        daoSession = daoMaster.newSession();
    }

This is the only place where I am accessing the db using helper.getWritableDatabase().

Everywhere else I am using the daoSession object to access db.

Stacktrace:

java.lang.RuntimeException: Unable to create application o.ᴛ: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4608)
       at android.app.ActivityThread.access$1500(ActivityThread.java:148)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1353)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:135)
       at android.app.ActivityThread.main(ActivityThread.java:5312)
       at java.lang.reflect.Method.invoke(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
       at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
       at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
       at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
       at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
       at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
       at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
       at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
       at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
       at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
       at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
       at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806)
       at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791)
       at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
       at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:1276)
       at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:267)
       at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
       at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
       at o.ᴛ.onCreate(SourceFile:1032)
       at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1034)
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4605)
       at android.app.ActivityThread.access$1500(ActivityThread.java:148)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1353)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:135)
       at android.app.ActivityThread.main(ActivityThread.java:5312)
       at java.lang.reflect.Method.invoke(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
@Groxx
Copy link

Groxx commented Jun 4, 2015

It probably means you're creating multiple DbUpdateHelper instances. You almost always only want to make one, ever.

@KushGoyal
Copy link
Author

Hi,

Thanks for the help. Will using a singleton pattern solve this bug?

@Groxx
Copy link

Groxx commented Jun 4, 2015

If that's the cause, yes. I think you can (and should) just make a single DaoSession as well, so you can just make the session into a singleton. I forget exactly what goes into DaoSession though, so I could be wrong on that - check the docs :)

@KushGoyal
Copy link
Author

I think I cannot make DbUpdateHelper singleton because the static instance will hold a reference to the context which will not get garbage collect until classloader has been unloaded which is I think almost never.

Is there any other solution I can implement to prevent multiple instances of DbUpdateHelper. Although I still don't understand how is it even possible that there are multiple instances of DbUpdateHelper since I am using the code in the application class and not anywhere else.

@zhangsl
Copy link

zhangsl commented Dec 17, 2015

I got a similar crash, I have a singleton DatabaseHelper, and no transaction operation, but still crash

@hwldzh
Copy link

hwldzh commented Dec 22, 2015

you can use context.getapplicationcontext, then the context can be collect by the garbage

@michal-luszczuk
Copy link

Did you solve this issue?
Because i'm also facing this problem.
App is crashing while first getWritableDatabasecall. And this call is done inside Application object. So nothing should be called before.

@donghuipei
Copy link

@michal-luszczuk
My issue is like you, I found the cause of the problem is a process that would correspond to a target application, if your application is configured with additional process, you might have multiple processes simultaneously open db operation, causing database locks abnormal.

@michal-luszczuk
Copy link

michal-luszczuk commented Jul 27, 2016

@donghuipei
Yeah, I've got same problem - multi-proces app related (database was initiated in Application class onCreate() method which was called by each process separately)

@donghuipei
Copy link

donghuipei commented Jul 27, 2016

@michal-luszczuk
If only the main process in the application database operations there, while other applications related to the process does not require operation of the database, I recommend to initialize the database plus operating conditions, like this:

    if(getCurProcessName(getApplicationContext()).equals("replace your application package name")){
        // initialize the database
    }



private String getCurProcessName(Context context) {
    int pid = android.os.Process.myPid();
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningAppProcessInfo appProcess : activityManager.getRunningAppProcesses()) {
        if (appProcess.pid == pid) {
            return appProcess.processName;
        }
    }
    return "";
}

@michal-luszczuk
Copy link

@donghuipei
That's right (I did the same), and probably this is the best solution.
I think this answer will help many devs :)

@ashalmawia
Copy link

I wonder what's the solution in case if multiple processes need accessing the same SQLite database...

@greenrobot-team
Copy link
Collaborator

greenrobot-team commented Apr 25, 2017

@artesa Based on a quick Google search using a ContentProvider is the common solution to access a (SQLite) database from another process/app. -ut

@ashalmawia
Copy link

@greenrobot-team Clever but nonconstructive, and I can explain why. SQLite documentation states that SQLite should support multiprocess access out-of-box. Using a ContentProvider is basically accessing SQLite database from a single process, while accessing the provider itself happens in a multiprocess manner. Therefore, it seems like the problem lies in Google's implementation of SQLiteOpenHelper, which makes multiprocess access done through it unreliable while you keep the connection open (and, of course, there is a plenty of other problems in case you don't).

I reached some progress in struggling with the issue, but still was not able to get rid of it completely. That's why I'm interested whether anyone was more successful.

BTW, I don't believe ContentProviders are actually a panacea. The library based on them which we used was generating even more errors on heavy loads than accessing SQLite directly. Was it the problem of the library? Maybe. But it's rather popular and we failed to find the reason in code, which itself makes providers either unreliable or hard to set up properly in some cases.

As a generalization of your comment I could add the following: based on a quick Google search (hint) dividing your app into multiple processes is strictly discouraged in principle. Yep, that's true. But, would this knowledge help me to deal with that huge ton of legacy? Don't think so. :)

@hooby3dfx
Copy link

I am also seeing this happen occasionally in an app that I work on, but the app is not designed to use multiple processes.
That being the case, when would this happen? Would that PID check still be useful?

@nickylin
Copy link

I'm occurred this problem, so we do not use greendao for multi process?
`

Thread Name: 'ModelWriteWorkThread'

  |   | Back traces starts.
  |   | android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
  |   | at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
  |   | at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:915)
  |   | at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:755)
  |   | at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
  |   | at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1771)

`

@xurui1995
Copy link

@michal-luszczuk
I got the exception and i didnt use GreenDao.
Multiple processes were used in my app, but only one processes used Sqlite.
have u solve it?

@michal-luszczuk
Copy link

@xurui1995
Like I said before. Problem is solved for us.
The case was related to opening/initializing greenDao/sqlite db in code which was called by multiple processes.

You should check in which process code is called (using This comment ) and this should resolve your problems.

@nickylin
Copy link

nickylin commented Aug 14, 2017

if we need to read or write db in multi process, how we do to solve this problem? @michal-luszczuk @donghuipei

Repository owner deleted a comment from zxy198717 Nov 13, 2017
@EnvySongtao
Copy link

I have the similar crash,just becouse,I write self Application but forget to set appliaction name in manifest.xml

@abduldblogger
Copy link

Hi,
Use :
database = dbHelper.getWritableDatabase();
database.enableWriteAheadLogging(); // this will allow transactions from multiple threads.

Please read https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#enableWriteAheadLogging%28%29

I hope this will help.

@gwheet
Copy link

gwheet commented Feb 27, 2018

Found how to solve it. The problem for me was that I created multiple instances of SQLiteOpenHelper for the same database file from multiple threads. getWritableDatabase() contains synchronized block inside to prevent parallel access to internal open() method from multiple threads but because as I said there were multiple instances of SQLiteOpenHelper this lock didn't work. I created singleton from SQLiteOpenHelper. In order to release memory, I used WeakReference for "instance" field.
Also, you probably want to add enableWriteAheadLogging() in order to access db methods in parallel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests