我在android上使用SQLite数据库。我的数据库管理器是一个单例,现在正在初始化时打开与数据库的连接。将数据库保持打开状态是安全的,这样当有人调用我的类来处理数据库时,它已经打开了吗?或者我应该在每次访问之前和之后打开和关闭数据库。只是让它一直打开是否有任何伤害?
谢谢!
答案 0 :(得分:60)
我会一直打开它,并在onStop
或onDestroy
等生命周期方法中关闭它。这样,您可以在每次使用之前通过在单个isDbLockedByCurrentThread
对象上调用isDbLockedByOtherThreads
或SQLiteDatabase
来轻松检查数据库是否已被使用。这将阻止对数据库的多次操作,并使您的应用程序免于潜在的崩溃
所以在你的单身人士中,你可能有一个像这样的方法来获得你的单个SQLiteOpenHelper
对象:
private SQLiteDatabase db;
private MyDBOpenHelper mySingletonHelperField;
public MyDBOpenHelper getDbHelper() {
db = mySingletonHelperField.getDatabase();//returns the already created database object in my MyDBOpenHelper class(which extends `SQLiteOpenHelper`)
while(db.isDbLockedByCurrentThread() || db.isDbLockedByOtherThreads()) {
//db is locked, keep looping
}
return mySingletonHelperField;
}
所以无论何时你想使用你的开放助手对象,都要调用这个getter方法(确保它是有线程的)
你的单身人士的另一种方法可能是(在你试图调用上面的getter之前每隔一段时间调用一次):
public void setDbHelper(MyDBOpenHelper mySingletonHelperField) {
if(null == this.mySingletonHelperField) {
this.mySingletonHelperField = mySingletonHelperField;
this.mySingletonHelperField.setDb(this.mySingletonHelperField.getWritableDatabase());//creates and sets the database object in the MyDBOpenHelper class
}
}
您可能也希望关闭单例中的数据库:
public void finalize() throws Throwable {
if(null != mySingletonHelperField)
mySingletonHelperField.close();
if(null != db)
db.close();
super.finalize();
}
如果您的应用程序的用户能够非常快速地创建许多数据库交互,您应该使用我上面演示过的内容。但是如果有最小的数据库交互,我不会担心它,只是每次创建和关闭数据库。
答案 1 :(得分:20)
截至目前,无需检查数据库是否被另一个线程锁定。
当您在每个线程中使用单例SQLiteOpenHelper时,您是安全的。
来自isDbLockedByCurrentThread
文档:
自API级别16以来,此方法的名称来自活动时的名称 连接到数据库意味着该线程持有一个实际的 锁定数据库。如今,不再是一个真正的数据库 锁"虽然线程可能会阻止,如果他们无法获取数据库 连接以执行特定操作。
isDbLockedByOtherThreads
已被弃用。
答案 2 :(得分:12)
关于问题:
我的数据库管理器是一个单例,现在正在初始化时打开与数据库的连接。
我们应该分开打开DB'打开连接'。 SQLiteOpenHelper.getWritableDatabase()给出了一个打开的数据库。 但我们不必像在内部那样控制连接。
将数据库保持打开状态是安全的,这样当有人调用我的类来处理数据库时,它已经打开了吗?
是的,确实如此。如果正确关闭了事务,则连接不会挂起。请注意,如果GC最终确定,您的数据库也将自动关闭。
或者我应该在每次访问之前和之后打开和关闭数据库。
关闭SQLiteDatabase实例除了关闭连接之外没有任何重要意义,但如果此时有一些连接,这是一个开发人员的错误。此外,在SQLiteDatabase.close()之后,SQLiteOpenHelper.getWritableDatabase()将返回一个新实例。
一直把它打开是否有任何伤害?
不,没有。另请注意,在不相关的时刻和线程关闭数据库,例如在Activity.onStop()中可能会关闭活动连接并使数据处于不一致状态。
答案 3 :(得分:1)
Android 8.1有一个SQLiteOpenHelper.setIdleConnectionTimeout(long)
方法:
设置SQLite连接的最大毫秒数 在关闭并从池中移除之前允许闲置。
答案 4 :(得分:1)
从性能角度来看,最佳方法是在应用程序级别保留单个SQLiteOpenHelper实例。打开数据库可能很昂贵并且是一个阻塞操作,因此不应该在主线程和/或活动生命周期方法中完成。
当数据库不使用时,setIdleConnectionTimeout()方法(在Android 8.1中引入)可用于释放RAM。如果设置了空闲超时,则在一段不活动时间(即未访问数据库时)将关闭数据库连接。当执行新查询时,将以透明方式重新打开连接。
除此之外,应用可以在进入后台时调用releaseMemory()或检测内存压力,例如在onTrimMemory()
答案 5 :(得分:0)
您也可以使用ContentProvider。它会为你做这件事。
答案 6 :(得分:-9)
创建您自己的应用程序上下文,然后从那里打开和关闭数据库。 该对象还有一个可用于关闭连接的OnTerminate()方法。 我还没有尝试过,但这似乎是一种更好的方法。
@binnyb:我不喜欢使用finalize()来关闭连接。 可能会工作,但据我所知,在Java finalize()方法中编写代码是一个坏主意。