Android SQLite DB 何时关闭
Posted
技术标签:
【中文标题】Android SQLite DB 何时关闭【英文标题】:Android SQLite DB When to Close 【发布时间】:2011-06-01 05:24:53 【问题描述】:我正在使用 android 上的 SQLite 数据库。我的数据库管理器是一个单例,现在在初始化时打开与数据库的连接。让数据库一直保持打开状态是安全的,这样当有人打电话给我的班级使用数据库时,它已经打开了吗?或者我应该在需要每次访问之前和之后打开和关闭数据库。一直开着有什么坏处吗?
谢谢!
【问题讨论】:
【参考方案1】:我会一直保持打开状态,并以某种生命周期方法关闭它,例如onStop
或onDestroy
。这样,您可以在每次使用之前通过在单个 SQLiteDatabase
对象上调用 isDbLockedByCurrentThread
或 isDbLockedByOtherThreads
轻松检查数据库是否已在使用中。这将防止对数据库进行多次操作并避免您的应用程序崩溃
所以在你的单例中,你可能有这样的方法来获取你的单个 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();
如果您的应用程序的用户能够非常快速地创建许多数据库交互,您应该使用我上面演示过的东西。但是如果数据库交互很少,我就不用担心了,每次都创建和关闭数据库。
【讨论】:
我可以使用这种方法将数据库访问速度提高 2 倍(保持数据库打开),谢谢 纺纱是一种非常糟糕的技术。请参阅下面的答案。 @mixel 好点。我相信我在 API 16 可用之前发布了这个答案,但我可能是错的 @binnyb 我认为最好更新您的答案,以免误导人们。 WARN isDbLockedByOtherThreads() 自 API 16 以来已弃用并返回 false。同时检查 isDbLockedByCurrentThread() 将提供无限循环,因为它会停止当前线程并且没有任何东西可以“解锁 DB”,因此此方法返回 true。 【参考方案2】:到目前为止,无需检查数据库是否被另一个线程锁定。
当您在每个线程中使用单例 SQLiteOpenHelper 时,您是安全的。
来自isDbLockedByCurrentThread
文档:
这个方法的名字来自一个活跃的时间 与数据库的连接意味着线程持有一个实际的 锁定数据库。如今,已经没有真正的“数据库 锁”,尽管如果线程无法获取数据库,它们可能会阻塞 连接以执行特定操作。
isDbLockedByOtherThreads
自 API 级别 16 起已弃用。
【讨论】:
每个线程使用一个实例是没有意义的。 SQLiteOpenHelper 是线程安全的。这也是非常低效的内存。相反,应用程序应该为每个数据库保留一个 SQLiteOpenHelper 实例。为了获得更好的并发性,建议使用 WriteAheadLogging,它为最多 4 个连接提供连接池。 @ejboy 我是这个意思。 “在每个线程中使用单例(= 一个)SQLiteOpenHelper”,而不是“每个线程”。【参考方案3】:关于问题:
我的数据库管理器是单例的,在初始化时会立即打开与数据库的连接。
我们应该划分'opening DB','opening a connection'。 SQLiteOpenHelper.getWritableDatabase() 给出一个打开的数据库。 但是我们不必控制连接,因为它是在内部完成的。
让数据库一直打开是安全的,这样当有人打电话给我的班级使用数据库时,它已经打开了吗?
是的,是的。如果事务正确关闭,连接不会挂起。请注意,如果 GC 完成,您的数据库也会自动关闭。
或者我应该在每次访问之前和之后打开和关闭数据库。
关闭 SQLiteDatabase 实例除了关闭连接之外并没有什么大不了的,但如果此时有一些连接,这对开发人员来说很糟糕。此外,在 SQLiteDatabase.close() 之后,SQLiteOpenHelper.getWritableDatabase() 将返回一个新实例。
一直开着有什么坏处吗?
不,没有。另请注意,在不相关的时刻关闭数据库和线程,例如在 Activity.onStop() 中可能会关闭活动连接并使数据处于不一致状态。
【讨论】:
谢谢你,在阅读了你的话“在 SQLiteDatabase.close() 之后,SQLiteOpenHelper.getWritableDatabase() 将返回一个新实例”后,我意识到我终于找到了我应用程序的一个老问题的答案.对于迁移到 Android 9 后变得至关重要的问题(请参阅***.com/a/54224922/297710)【参考方案4】:Android 8.1 有一个SQLiteOpenHelper.setIdleConnectionTimeout(long)
方法:
设置 SQLite 连接的最大毫秒数 在关闭并从池中移除之前允许处于空闲状态。
https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#setIdleConnectionTimeout(long)
【讨论】:
这些天它已被弃用。【参考方案5】:从性能的角度来看,最佳方法是在应用程序级别保留一个 SQLiteOpenHelper 实例。打开数据库可能很昂贵并且是一个阻塞操作,因此不应该在主线程和/或活动生命周期方法中完成。
setIdleConnectionTimeout() 方法(在 Android 8.1 中引入)可用于在不使用数据库时释放 RAM。如果设置了空闲超时,数据库连接将在一段时间不活动后关闭,即当数据库未被访问时。执行新查询时,将对应用透明地重新打开连接。
除此之外,应用程序可以在进入后台或检测到内存压力时调用releaseMemory(),例如在onTrimMemory()
【讨论】:
【参考方案6】:您也可以使用 ContentProvider。它会为你做这些事情。
【讨论】:
【参考方案7】:创建您自己的应用程序上下文,然后从那里打开和关闭数据库。 该对象还具有可用于关闭连接的 OnTerminate() 方法。 我还没有尝试过,但它似乎是一个更好的方法。
@binnyb:我不喜欢使用 finalize() 来关闭连接。 可能可行,但据我了解,在 Java finalize() 方法中编写代码是个坏主意。
【讨论】:
你不想依赖 finalize 因为你永远不知道它什么时候会被调用。在 GC 决定清理它之前,一个对象可能会一直处于不确定状态,然后才会调用 finalize()。这就是它没用的原因。正确的做法是在对象不再使用时调用一个方法(不管是否被垃圾收集),而这正是 onTerminate() 的作用。 文档说得很清楚,onTerminate
不会在生产环境中被调用 - developer.android.com/reference/android/app/…以上是关于Android SQLite DB 何时关闭的主要内容,如果未能解决你的问题,请参考以下文章
将 Android 应用上的 SQLite DB 与远程 MySQL DB 同步
将本地 HTML5 DB(WebSQL 存储,SQLite)与服务器同步的最佳方法(2 路同步)[关闭]
Android 数据存储,何时使用 Sqlite,何时使用 JSON,Linq 替代方案