SQLite数据库并发访问

SQLite数据库并发访问,第1张

概述译自:https://github.com/dmytrodanylyk/dmytrodanylyk/blob/gh-pages/articles/Concurrent%20Database%20Access.md 我曾经写过一篇很简短的文章,阐述了线程安全的访问android sqlite数据库。样例程序可以在这里获取到。 /////////////////////////////////////
译自:https://github.com/dmytrodanylyk/dmytrodanylyk/blob/gh-pages/articles/Concurrent%20Database%20Access.md
我曾经写过一篇很简短的文章,阐述了线程安全的访问androID sqlite数据库。样例程序可以在这里获取到。
///////////////////////////////////////华丽的分割线//////////////////////////////////////
假设你已经有一个自己的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,实际上你每次都创建了一个数据库的连接。如果你在同一时间用不同的数据库连接来对同一的数据库进行写 *** 作的话,那么其中一个会失败。
在AndroID平台上,如果你想在多线程环境下安全的使用数据库的话,那么你得确保所有的线程使用的都是同一个数据库连接。
确保只有一个数据库连接存在,我们可以使用单例模式,代码如下
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 new mDatabaseHelper.getWritableDatabase();    }}
现在我们来看看执行结果
// In your application class DatabaseManager.initializeInstance(getApplicationContext()); // Thread 1 DatabaseManager manager = DatabaseManager.getInstance(); sqliteDatabase database = manager.getDatabase() database.insert(// Thread 2 DatabaseManager manager = DatabaseManager.getInstance(); sqliteDatabase database = manager.getDatabase() database.insert(); database.close();
你的应用将会崩溃,异常信息如下
java.lang.IllegalStateException: attempt to re-open an already-closed object: sqliteDatabase
因为我们只使用一个数据库连接,Thread1和Thread2的都是由getDatabase()方法返回的相同连接。发生的什么事呢,在Thread2还在使用数据库连接时,Thread1可能已经把它给关闭了,那就是为什么你会得到崩溃异常。
我们需要确保在没有任何一个人在使用数据库时,才去关闭它。在StackOverflow上推荐的做法是永远不要关闭数据库。AndroID会尊重你这种做法,但会给你如下的提示。所以我一点也不推荐这种做法。
Leak found
Caused by: java.lang.IllegalStateException: sqliteDatabase created and never closed
下面是一个样例程序
DatabaseManager {    private AtomicInteger mOpenCounter = new AtomicInteger();    private static DatabaseManager instance;    private static sqliteOpenHelper mDatabaseHelper;    private sqliteDatabase mDatabase;    public static synchronized initializeInstance(sqliteOpenHelper helper) {        if (instance == null) {            instance = new DatabaseManager();            mDatabaseHelper = helper;        }    }    public static synchronized DatabaseManager );        }        return instance;    }    public synchronized sqliteDatabase openDatabase() {        if(mOpenCounter.incrementAndGet() == 1) {            // opening new database            mDatabase = mDatabaseHelper.getWritableDatabase();        }        return mDatabase;    }    public synchronized 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,则需要创建一个数据库,如果不为1,说明我们已经创建过了。
在closeDatabase()方法中我们同样通过判断引用计数的值,如果引用计数降为0,则说明我们需要close数据库。 总结

以上是内存溢出为你收集整理的SQLite数据库并发访问全部内容,希望文章能够帮你解决SQLite数据库并发访问所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1172684.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-02
下一篇 2022-06-02

发表评论

登录后才能评论

评论列表(0条)

保存