Android多线程下安全访问数据库
来源:互联网 发布:h5微信支付 java 编辑:程序博客网 时间:2024/05/18 02:29
为了记录如何线程安全地访问你的Android数据库实例,我写下了这篇小小札记。文章中引用的项目代码请点击这里
假设你已编写了自己的 SQLiteOpenHelper。
然后在你的Logcat中将输出类似下面的日志信息,而你的写数据操作将会无效。
上面问题的出现,源于你每创建一个 SQLiteOpenHelper 对象时,实际上也是在新建一个数据库连接。如果你尝试通过多个连接同时对数据库进行写数据操作,其一定会失败。
为确保我们能在多线程中安全地操作数据库,我们需要保证只有一个数据库连接被占用。
我们先编写一个负责管理单个 SQLiteOpenHelper 对象的单例 DatabaseManager 。
既然我们只有一个数据库连接,Thread1 和 Thread2 对方法 getDatabase() 的调用就会取得一样的 SQLiteDatabase 对象实例。之后的事情就是,当 Thread1 尝试管理数据库连接时,Thread2 却仍然在使用该数据库连接。这也就是导致 IllegalStateException 崩毁的原因。
因此我们只能在确保数据库没有再被占用的情况下,才去关闭它。在 stackoveflow 上有一些讨论推荐“永不关闭”你的 SQLiteDatabase 。 如果你这样做,你的logcat将会出现以下的信息,因此我不认为这是一个好主意。
Leak foundCaused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed
示例:
然后你可以怎样子去调用它:
以后每当你需要使用数据库连接,你可以通过调用类 DatabaseManager 的方法openDatabase()。在方法里面,内置一个标志数据库被打开多少次的计数器。如果计数为1,代表我们需要打开一个新的数据库连接,否则,数据库连接已经存在。
在方法 closeDatabase() 中,情况也一样。每次我们调用 closeDatabase() 方法,计数器都会递减,直到计数为0,我们就需要关闭数据库连接了。
提示: 你应该使用 AtomicInteger 来处理并发的情况
现在你可以线程安全地使用你的数据库连接了。
原文: https://github.com/dmytrodanylyk/dmytrodanylyk/blob/gh-pages/articles/Concurrent%20Database%20Access.md
假设你已编写了自己的 SQLiteOpenHelper。
- public class DatabaseHelper extends SQLiteOpenHelper { ... }
现在你想在不同的线程中对数据库进行写数据操作:
- // Thread 1
- Context context = getApplicationContext();
- DatabaseHelper helper = new DatabaseHelper(context);
- SQLiteDatabase database = helper.getWritableDatabase();
- database.insert(…);
- database.close();
- // Thread 2
- Context context = getApplicationContext();
- DatabaseHelper helper = new DatabaseHelper(context);
- SQLiteDatabase database = helper.getWritableDatabase();
- database.insert(…);
- database.close();
然后在你的Logcat中将输出类似下面的日志信息,而你的写数据操作将会无效。
- android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
上面问题的出现,源于你每创建一个 SQLiteOpenHelper 对象时,实际上也是在新建一个数据库连接。如果你尝试通过多个连接同时对数据库进行写数据操作,其一定会失败。
为确保我们能在多线程中安全地操作数据库,我们需要保证只有一个数据库连接被占用。
我们先编写一个负责管理单个 SQLiteOpenHelper 对象的单例 DatabaseManager 。
- public class DatabaseManager {
- private static DatabaseManager instance;
- private static SQLiteOpenHelper mDatabaseHelper;
- public static synchronized void initialize(Context context, SQLiteOpenHelper helper) {
- if (instance == null) {
- instance = new DatabaseManager();
- mDatabaseHelper = helper;
- }
- }
- public static synchronized DatabaseManager getInstance() {
- if (instance == null) {
- throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
- " is not initialized, call initialize(..) method first.");
- }
- return instance;
- }
- public synchronized SQLiteDatabase getDatabase() {
- return mDatabaseHelper.getWritableDatabase();
- }
- }
- <span style="font-size:18px;">// In your application class
- DatabaseManager.initializeInstance(getApplicationContext());
- // Thread 1
- DatabaseManager manager = DatabaseManager.getInstance();
- SQLiteDatabase database = manager.getDatabase()
- database.insert(…);
- database.close();
- // Thread 2
- DatabaseManager manager = DatabaseManager.getInstance();
- SQLiteDatabase database = manager.getDatabase()
- database.insert(…);
- database.close();</span>
- java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase
既然我们只有一个数据库连接,Thread1 和 Thread2 对方法 getDatabase() 的调用就会取得一样的 SQLiteDatabase 对象实例。之后的事情就是,当 Thread1 尝试管理数据库连接时,Thread2 却仍然在使用该数据库连接。这也就是导致 IllegalStateException 崩毁的原因。
因此我们只能在确保数据库没有再被占用的情况下,才去关闭它。在 stackoveflow 上有一些讨论推荐“永不关闭”你的 SQLiteDatabase 。 如果你这样做,你的logcat将会出现以下的信息,因此我不认为这是一个好主意。
Leak foundCaused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed
示例:
- public class DatabaseManager {
- private AtomicInteger mOpenCounter = new AtomicInteger();
- private static DatabaseManager instance;
- private static SQLiteOpenHelper mDatabaseHelper;
- private SQLiteDatabase mDatabase;
- public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
- if (instance == null) {
- instance = new DatabaseManager();
- mDatabaseHelper = helper;
- }
- }
- public static synchronized DatabaseManager getInstance() {
- if (instance == null) {
- throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
- " is not initialized, call initializeInstance(..) method first.");
- }
- return instance;
- }
- public synchronized SQLiteDatabase openDatabase() {
- if(mOpenCounter.incrementAndGet() == 1) {
- // Opening new database
- mDatabase = mDatabaseHelper.getWritableDatabase();
- }
- return mDatabase;
- }
- public synchronized void closeDatabase() {
- if(mOpenCounter.decrementAndGet() == 0) {
- // Closing database
- mDatabase.close();
- }
- }
- }
然后你可以怎样子去调用它:
SQLiteDatabase database = DatabaseManager.getInstance().openDatabase();database.insert(...);// database.close(); Don't close it directly!DatabaseManager.getInstance().closeDatabase(); // correct way
以后每当你需要使用数据库连接,你可以通过调用类 DatabaseManager 的方法openDatabase()。在方法里面,内置一个标志数据库被打开多少次的计数器。如果计数为1,代表我们需要打开一个新的数据库连接,否则,数据库连接已经存在。
在方法 closeDatabase() 中,情况也一样。每次我们调用 closeDatabase() 方法,计数器都会递减,直到计数为0,我们就需要关闭数据库连接了。
提示: 你应该使用 AtomicInteger 来处理并发的情况
现在你可以线程安全地使用你的数据库连接了。
原文: https://github.com/dmytrodanylyk/dmytrodanylyk/blob/gh-pages/articles/Concurrent%20Database%20Access.md
0 0
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- Android多线程下安全访问数据库
- [Android][转]Android多线程下安全访问数据库
- 【Android】SQLite实例(多线程下安全访问数据库)
- Android中多线程访问数据库、DBHelper
- 数据库-多线程安全
- 无法在当前安全上下文下访问数据库
- 多线程环境下SQLite数据库并发访问的解决方案
- 多线程访问数据库
- SSLSocket passphrase/password in Python
- [Cocoa]_[初级]_[自定义的界面上绘制图片]
- daohanglan
- 加盟声讯电话 代理加值电话
- awk使用方法笔记
- Android多线程下安全访问数据库
- 供应加值电话 真的手机吸费 轻松在家赚钱
- 打电话就赚钱 吸费电话原理 全国连锁
- 什么的吸费电话 手机吸费怎么合作
- why
- hdu1147:pick up sticks
- jdk环境变量配置
- 黑马程序员—————变量
- 黑马程序员------class 类