Android SQLite DB何时关闭

时间:2010-12-29 19:25:48

标签: android sqlite

我在android上使用SQLite数据库。我的数据库管理器是一个单例,现在正在初始化时打开与数据库的连接。将数据库保持打开状态是安全的,这样当有人调用我的类来处理数据库时,它已经打开了吗?或者我应该在每次访问之前和之后打开和关闭数据库。只是让它一直打开是否有任何伤害?

谢谢!

7 个答案:

答案 0 :(得分:60)

我会一直打开它,并在onStoponDestroy等生命周期方法中关闭它。这样,您可以在每次使用之前通过在单个isDbLockedByCurrentThread对象上调用isDbLockedByOtherThreadsSQLiteDatabase来轻松检查数据库是否已被使用。这将阻止对数据库的多次操作,并使您的应用程序免于潜在的崩溃

所以在你的单身人士中,你可能有一个像这样的方法来获得你的单个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连接的最大毫秒数   在关闭并从池中移除之前允许闲置。

https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#setIdleConnectionTimeout(long)

答案 4 :(得分:1)

从性能角度来看,最佳方法是在应用程序级别保留单个SQLiteOpenHelper实例。打开数据库可能很昂贵并且是一个阻塞操作,因此不应该在主线程和/或活动生命周期方法中完成。

当数据库不使用时,

setIdleConnectionTimeout()方法(在Android 8.1中引入)可用于释放RAM。如果设置了空闲超时,则在一段不活动时间(即未访问数据库时)将关闭数据库连接。当执行新查询时,将以透明方式重新打开连接。

除此之外,应用可以在进入后台时调用releaseMemory()或检测内存压力,例如在onTrimMemory()

答案 5 :(得分:0)

您也可以使用ContentProvider。它会为你做这件事。

答案 6 :(得分:-9)

创建您自己的应用程序上下文,然后从那里打开和关闭数据库。 该对象还有一个可用于关闭连接的OnTerminate()方法。 我还没有尝试过,但这似乎是一种更好的方法。

@binnyb:我不喜欢使用finalize()来关闭连接。 可能会工作,但据我所知,在Java finalize()方法中编写代码是一个坏主意。