2012-04-26 4 views
1

로컬 SQLite 데이터베이스에서 긴 삭제 작업을 수행하는 AsyncTask를 실행할 때 문제가 있습니다. 사용자가 화면을 회전하면 AsyncTask가 실행되는 동안 Activity가 다시 작성되고 데이터베이스에 대한 새 연결이 만들어집니다. ...Android SQLite의 동시성 문제

내가 SQLite는 한 번에 여러 읽기와 하나 개 쓰기를 지원하는지 알고, 이것은 삭제가 수행되는 동안로 읽을 수있는 데이터베이스를 열 때 충돌이 왜 그렇게 이해하지 않는 경우 것

실패는 다음과 같습니다

04-26 12:54:21.839: I/Database(3925): sqlite returned: error code = 5, msg = database is locked 
04-26 12:54:21.839: E/Database(3925): SELECT locale FROM android_metadata failed 
04-26 12:54:21.839: E/Database(3925): Failed to setLocale() when constructing, closing the database 
04-26 12:54:21.839: E/Database(3925): android.database.sqlite.SQLiteException: database is locked 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.native_setLocale(Native Method) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.setLocale(SQLiteDatabase.java:1967) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1835) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:820) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:197) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:172) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.open(DatabaseManager.java:157) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.<init>(DatabaseManager.java:147) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.openerp.models.ConnectionProfile$ConnectionProfileManager.<init>(ConnectionProfile.java:138) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.activities.SelectConnectionProfile.fillData(SelectConnectionProfile.java:71) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.activities.SelectConnectionProfile.onResume(SelectConnectionProfile.java:66) 
04-26 12:54:21.839: E/Database(3925): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1149) 
04-26 12:54:21.839: E/Database(3925): at android.app.Activity.performResume(Activity.java:3833) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2085) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2110) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1643) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2796) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.access$1600(ActivityThread.java:117) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:932) 
04-26 12:54:21.839: E/Database(3925): at android.os.Handler.dispatchMessage(Handler.java:99) 
04-26 12:54:21.839: E/Database(3925): at android.os.Looper.loop(Looper.java:123) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.main(ActivityThread.java:3647) 
04-26 12:54:21.839: E/Database(3925): at java.lang.reflect.Method.invokeNative(Native Method) 
04-26 12:54:21.839: E/Database(3925): at java.lang.reflect.Method.invoke(Method.java:507) 
04-26 12:54:21.839: E/Database(3925): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
04-26 12:54:21.839: E/Database(3925): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
04-26 12:54:21.839: E/Database(3925): at dalvik.system.NativeStart.main(Native Method) 

내가 다음 해결 방법을 코딩,하지만 난이 매우 정중 아니라고 생각 :

private void openReadableDatabaseWithForeignKeySupport() { 
    try { 
     mDatabase = mDatabaseHelper.getReadableDatabase(); 
     mDatabase.execSQL("PRAGMA foreign_keys = ON"); 
    } catch (SQLiteException e) { 
     /* 
     * If there is an exception because the database is locked, 
     * we will retry until it is free and can be opened. 
     * */ 
     Log.d(getClass().getName(), e.toString()); 
     openReadableDatabaseWithForeignKeySupport(); // Recursive call 
    } 
} 
,

가장 호기심은 실패 할 것 같다 무엇 안드로이드에 의해 자동으로 호출 setLocale() 방법이다, 그러나 docs는 말한다 :

로 setLocale()이 데이터베이스에 대한 로케일을 설정합니다. 이 데이터베이스에 NO_LOCALIZED_COLLATORS 플래그가 설정되어 있거나 읽기 전용으로 열린 경우 아무 것도 수행하지 않습니다.

도움이 될 것입니다. :)

+0

이 질문을 확인하십시오 : [SQLite 예외 : 데이터베이스 잠김 문제] (http://stackoverflow.com/questions/7657223/sqlite-exception-database-is-locked-issue) –

+0

또한 회전 할 때 활동을 재현하지 않으려면 android : configChanges = "keyboardHidden | orientation"을 AndroidManifest.xml의 활동 정의에 추가 할 수 있습니다. – DustinB

답변

2

이렇게 정기적으로 데이터베이스를 열고 닫는 것은 좋지 않습니다. 애플리케이션을 시작할 때 한 번 열어서 앱의 수명 기간 동안이 연결을 재사용하십시오. 그것을 닫을 필요조차 없습니다. SQLite는 동시성을 관리하므로 다중 스레드에 대해 걱정할 필요가 없습니다.

이렇게하면 모든 "데이터베이스 잠김"오류가 사라지고 코드를 더 간결하고 간단하게 만들 수 있습니다.

+0

안녕하세요! 빠른 답변 주셔서 감사합니다! :) 그렇다면 데이터베이스를 보유 할 싱글 톤을 만들겠습니까? 맞습니까? 데이터베이스를 닫지 않는 것이 좋지 않은가요? – Caumons

+0

나는 이미 이것을 구현했고 잘 작동했다. 그러나, 나는 의심의 여지가있다 ... 내가 싱글 톤 인스턴스를 동기화해야하거나 필요하지 않습니다 (실제로는 자체가 수정되지 않으므로)? 당신의 대답에 대해 정말 고마워요! – Caumons

+0

동기화 할 필요가 없으며 데이터베이스를 닫을 필요가 없습니다. 모든 데이터베이스 쓰기는 가능한 한 빠른 시일 내에 저장소에 저장되므로 닫는 것은 아무런 이점이 없습니다. –