Android le filetage et le verrouillage de base de données
Nous utilisons AsyncTasks
pour accéder à la base de données les tables et les curseurs.
Malheureusement, nous voyons parfois des exceptions concernant la base de données verrouillée.
E/SQLiteOpenHelper(15963): Couldn't open iviewnews.db for writing (will try read-only):
E/SQLiteOpenHelper(15963): android.database.sqlite.SQLiteException: database is locked
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteDatabase.native_setLocale(Native Method)
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteDatabase.setLocale(SQLiteDatabase.java:1637)
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1587)
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:638)
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:659)
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:652)
E/SQLiteOpenHelper(15963): at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:482)
E/SQLiteOpenHelper(15963): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193)
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
E/SQLiteOpenHelper(15963): at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:158)
E/SQLiteOpenHelper(15963): at com.iview.android.widget.IViewNewsTopStoryWidget.initData(IViewNewsTopStoryWidget.java:73)
E/SQLiteOpenHelper(15963): at com.iview.android.widget.IViewNewsTopStoryWidget.updateNewsWidgets(IViewNewsTopStoryWidget.java:121)
E/SQLiteOpenHelper(15963): at com.iview.android.async.GetNewsTask.doInBackground(GetNewsTask.java:338)
E/SQLiteOpenHelper(15963): at com.iview.android.async.GetNewsTask.doInBackground(GetNewsTask.java:1)
E/SQLiteOpenHelper(15963): at android.os.AsyncTask$2.call(AsyncTask.java:185)
E/SQLiteOpenHelper(15963): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:256)
E/SQLiteOpenHelper(15963): at java.util.concurrent.FutureTask.run(FutureTask.java:122)
E/SQLiteOpenHelper(15963): at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:648)
E/SQLiteOpenHelper(15963): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:673)
E/SQLiteOpenHelper(15963): at java.lang.Thread.run(Thread.java:1060)
Quelqu'un en avoir un exemple de code qui écrit à une base de données à partir d'un autre thread que celui de la lecture et comment pouvons-nous assurer la sécurité des threads.
Une suggestion que j'ai eu est d'utiliser un ContentProvider
, ce qui permettrait de gérer l'accès de la base de données à partir de plusieurs threads. Je vais regarder cela, mais est-ce la méthode recommandée de la manipulation d'un tel problème? Il semble plutôt lourd étant donné que nous parlons de devant ou de derrière.
Vous devez vous connecter pour publier un commentaire.
J'ai résolu ce même exception en s'assurant simplement que tous mes base de données s'ouvre avons ferme, et (plus important) pour assurer cette, rendant la portée de chaque instance de base de données en local UNIQUEMENT à la méthode qui en a besoin. ContentProvider est un bon, coffre-fort classe à utiliser lors de l'accès à une base de données à partir de plusieurs threads, mais aussi assurez-vous que vous êtes en utilisant de bonnes db pratiques:
close()
sur la db dans la même méthode dans laquelle il est ouvertclose()
sur les curseurs que vous obtenez à partir de la dbNous avons utilisé un
ContentProvider
à la fin. Cela est apparu clairement les problèmes.SQLiteOpenHelper
ce qui signifie qu'il n'existe qu'une seule connexion à la base de données et le sous-jacentSQLiteDatabase
prend en charge le verrouillage. Vous n'avez pas besoin d'un ContentProvider - assurez-vous de ne pas écrire à la DB à l'aide de 2 db connections. Cet article explique comment le verrouillage fonctionne sur Android. kagii.squarespace.com/journal/2010/9/10/...Avant un peu de code, nous allons reprendre certaines des approches:
Les sémaphores: de loin la meilleure solution présentée. Il va au cœur du problème: le partage de la ressource! Il permettra de traiter le verrouillage de l'accès à la base, éviter les conflits (
database is locked
).Java synchronisation: Une sorte de sémaphore de la mise en œuvre, mais moins sofisticated. À l'aide de
synchronized
vous ne sera pas facile à résoudre certains cas liés à des transactions.ContentProvider: mettre en œuvre
ContentProvider
résoudre le problème seulement pour certains cas (ou balayer le problème sous le tapis). Vous aurez encore confrontés aux mêmes problèmes. La différence est queContentProvider
modèle qui va vous guider pour ne pas faire quelques commum des erreurs lors de l'accès à la base de données Sqlite. Le ContentProvider docs dit: "Vous n'avez pas besoin d'un prestataire pour l'utilisation d'une base de données SQLite si l'utilisation est entièrement à l'intérieur de votre propre application."Presque obligatoire: garder les instances db local, appel
close()
sur la db dans la même méthode dans laquelle il est ouvert à l'aide definally
états,close()
sur les curseurs à l'aidefinally
déclarations, etc sont presque obligatoire pour éviter les problèmes à l'aide de Sqlite.Nous allons montrer un exemple de l'sémaphore solution présentée par la Mousse, que j'ai pris d' CL. et improoved pour couvrir les transactions.
Prendre en compte le fait que les bases de données SQLite sont à base de fichier et ne sont pas destinées à être en mesure d'être accessible dans un multi-termes de processus. Le meilleur de la procédure sur le mélange SQLite avec le multi-traitement à l'aide de sémaphores (acquérir(), release()) dans chaque base de données liées à l'accès.
Si vous créez un Db wrapper qui acquiert/communiqués d'un sémaphore global de votre DB accès thread-safe. En effet, cela signifie que vous pourriez obtenir une bootleneck parce que vous êtes des files d'attente de l'accès à la DB. Si en plus vous ne pouvez les envelopper l'accès à l'aide de sémaphores si c'est une opération qui modifie la base de données, si bien que vous êtes alterin la db, personne ne sera en mesure d'y accéder et d'attendre jusqu'à ce que le processus d'écriture a été accomplie.
Nous ne pouvions pas partager Db connexion avec plusieurs thread pour effectuer l'opération en lecture et écriture dans la base de données simultanément.Nous aurons à en faire l'unique objet de DB à l'aide de synchronisation concept et nous allons effectuer une tâche à la fois .Nous allons utiliser le pattern singleton pour rendre la base de données de l'objet et il sera partagé au sein de plusieurs threads.À un moment va effectuer la même tâche . ensuite, nous allons commencer d'autres tâches, ou toute autre opération sur DB .
Fournisseur de contenu n'est pas la solution de DB problème de verrouillage .
et d'écrire cette méthode dans votre YourSQLiteDataABse de la classe helper qui s'étend SQLiteOpenHelper Classe
Vous devez appeler
getWritableDatabase()
à partir d'une fonction plutôt que le constructeur de la db classe d'aide. Si la db classe helper objet est créé avecSQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
ou similaire, et puisgetWritableDatabase()
est appelé à partir d'une fonction, il va essayer de faire un appel synchrone DB provoquer un verrouillage de base de données d'exception.Vous parlent d'une seule action de l'utilisateur qui, à l'intérieur de votre programme, les causes de plusieurs threads pour exécuter plus d'une qui peut être accéder à la base de données en mode de mise à jour ?
C'est une mauvaise conception, de la période. Il n'y a aucun moyen pour vous de savoir l'ordre dans lequel les threads seront programmées par votre système d'exploitation (/VM), et, par conséquent, il n'existe aucun moyen pour vous de savoir l'ordre dans lequel les accès base de données qui va se passer, et qui est très probablement impliquer qu'il n'existe aucun moyen pour vous de savoir que les accès base de données sera toujours le cas dans l'ordre que vous attendez.
Tous les accès base de données généré par/à venir à partir d'une action de l'utilisateur doit être fait dans un seul thread.